/* ====================================================================
   Elasticspace stylesheet

   Mirror of 06-theme/elastic-26/style.css. The WordPress theme is the
   source of truth for the visual language; this file is a verbatim
   copy with only the WP theme-metadata header removed. Diff this file
   against the theme when either side moves so they stay in sync.

   Built on Tyler Sticka's named-column grid: text sits in the middle
   column; figures optionally span all three for edge-to-edge images
   without viewport-unit hacks.
   https://cloudfour.com/thinks/breaking-out-with-css-grid-layout/

   Inter is loaded via <link> tags from rsms.me in the page Layout
   (parallel to this stylesheet, not @import-chained).
   IBM Plex Mono is loaded from Google Fonts, used for tag display.

   §11 retains the .wp-block-* selectors verbatim so this file stays
   diff-clean against the theme. Those selectors are inert against
   Astro-emitted markup but harmless.
   ==================================================================== */


/* ====================================================================
   1. Design tokens
   ==================================================================== */

:root {
  /* Colour ----------------------------------------------------------- */
  --ink:         #000;       /* primary body text */
  --paper:       #fff;       /* page background */
  --muted:       #595959;    /* secondary / meta text — clearly less
                                prominent than --ink but readable.
                                ~7:1 contrast on white (WCAG AAA). */
  --rule:        #ccc;       /* divider rules */
  --rule-light:  #ddd;       /* subtle dividers */
  --accent:      #ffd900;    /* link / highlight accent */

  /* Typography ------------------------------------------------------- */
  --font:        Inter, 'Inter Fallback', sans-serif;
  --mono:        'IBM Plex Mono', ui-monospace, 'SF Mono', Consolas,
                 'Liberation Mono', Menlo, monospace;
  --size:        1.1em;
  --leading:     1.5;

  /* Meta material (date, taxonomy, posts-nav, "Read more") uses the
     same Inter family and same body size as everything else; only
     colour and weight differentiate it from prose. Always semantic —
     "muted" means "less prominent than body", regardless of mode.  */
  --meta-color:          var(--muted);
  --meta-weight:         400;

  /* Layout rhythm ---------------------------------------------------- */
  --column:         35em;
  --rhythm:         1em;
  --section-break:  6em;     /* big vertical gap between major blocks
                                 (post body -> footer, footer -> nav,
                                 .Footer top/bottom) */

  /* Link underlines -------------------------------------------------- */
  --underline:         3px;
  --underline-offset:  4px;

  /* Series — multi-image figures (see section 11a) ------------------- */
  --series-gap:        0.5em;       /* between image cells */
  --series-row-gap:    1.5em;       /* between rows when per-image captions are present */
  --series-cap-size:   1em;         /* captions read at body size — Müller-Brockmann */
  --series-aspect:     3 / 2;       /* uniform crop default; opt-out: --series-aspect: auto */
}

@supports (font-variation-settings: normal) {
  :root { --font: InterVariable, 'Inter Fallback', sans-serif; }
}

@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial');
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}


/* ====================================================================
   2. Reset
   ==================================================================== */

*, *::before, *::after { box-sizing: border-box; }

body, figure, blockquote,
h1, h2, h3, h4, h5, h6,
p, ul, ol {
  margin: 0;
  padding: 0;
}

ul, ol { list-style: none; }

img {
  display: block;
  max-width: 100%;
  height: auto;
}


/* ====================================================================
   2a. Body lists — editorial dated-row treatment
   The reset above zeroes margins/padding and removes bullets. This
   restores a scannable list style for Markdown-authored body content
   that mirrors the Selected notes / Related posts pattern: each item
   on its own row with a thin rule between, generous padding, no
   bullets. Specific component lists (.RelatedPosts-list,
   .Home-selectedNotes .archive-list, .ProjectCards) already redeclare
   their own list styles and remain untouched — :where() keeps
   specificity at 0,0,1 so any component selector beats this default.

   Applies to body content lists inside posts and pages — wherever
   content is rendered through the_content().
   ==================================================================== */

:where(.Main > article, .Main > section.Film) ul,
:where(.Main > article, .Main > section.Film) ol {
  margin: 0; padding: 0;
}

/* Direct body-content lists (top-level inside the post). Nested lists
   are handled separately so they don't get a row border that would
   break the indented hierarchy. */
:where(.Main > article > ul,
       .Main > article > ol,
       .Main > article > p + ul,
       .Main > article > p + ol,
       .Main > section.Film > ul,
       .Main > section.Film > ol) > li {
  padding: 0.5em 0;
  border-bottom: 1px solid var(--rule-light);
}

/* Last item in each list shouldn't have a bottom border — visually
   "closes" the list block. */
:where(.Main > article > ul,
       .Main > article > ol,
       .Main > section.Film > ul,
       .Main > section.Film > ol) > li:last-child {
  border-bottom: 0;
}

/* Ordered lists: restore decimal numbering but keep them inside the
   text column. The number sits to the left, slightly muted. */
:where(.Main > article, .Main > section.Film) > ol {
  list-style: decimal outside;
  padding-left: 1.4em;
}
:where(.Main > article, .Main > section.Film) > ol > li::marker {
  color: var(--meta-color);
}

/* Nested lists: indent, dotted-rule between items so nested level is
   visually quieter than the parent. Also drop the row border on the
   parent <li> so we don't double up. */
:where(.Main > article, .Main > section.Film) ul ul,
:where(.Main > article, .Main > section.Film) ul ol,
:where(.Main > article, .Main > section.Film) ol ul,
:where(.Main > article, .Main > section.Film) ol ol {
  padding-left: 1.4em;
  margin-top: 0.5em;
}
:where(.Main > article, .Main > section.Film) ul ul > li,
:where(.Main > article, .Main > section.Film) ul ol > li,
:where(.Main > article, .Main > section.Film) ol ul > li,
:where(.Main > article, .Main > section.Film) ol ol > li {
  padding: 0.25em 0;
  border-bottom: 0;
}


/* ====================================================================
   3. Typography
   ==================================================================== */

html {
  font-family: var(--font);
  font-feature-settings: 'liga' 1, 'calt' 1;
  line-height: var(--leading);
  color: var(--ink);
  background: var(--paper);
  font-size: var(--size);   /* every element inherits — meta, links, time, divs, etc. */
}

/* Headings flat: same size as body, hierarchy by weight. Generous
   padding-top on every heading level signals a section break and
   gives titles room to breathe. */
h1, h2, h3, h4, h5, h6 {
  font-size: 1em;
  font-weight: 700;
  padding-top: 2em;
}
.entry-title { padding-top: 4em; }   /* post title — more prominent break */

blockquote {
  margin-left: 0.5em;
  padding-left: 1em;
  box-shadow: -0.5em 0 var(--rule-light);
}

figcaption {
  padding-top: 0.5em;
  color: var(--muted);
}


/* ====================================================================
   4. Links — two flavours, no exceptions
     · BODY link  — yellow chunky underline, yellow fill on hover.
       Used inside post content. Default <a>.
     · META link  — no decoration, picks up its container's color.
       Hover: ink color + 1px yellow bottom border. Used for site
       nav, post footer (date/cat/tags), posts-navigation, archive
       "Read more", and any link inside a meta context.

   Anything that isn't body content uses the meta treatment. Choose
   one of the two — never invent a third style.
   ==================================================================== */

a {
  color: inherit;
  text-decoration: underline var(--accent);
  text-decoration-thickness: var(--underline);
  text-underline-offset: var(--underline-offset);
  transition: background 0.3s, color 0.3s, border-color 0.3s;
}

a:hover {
  background: var(--accent);
  color: var(--ink);
}

/* Dark mode: the hover background (yellow accent) is bright in both
   modes, so the text inside the highlight must be ink-on-yellow ≈
   black to remain readable. Without this override, the hover state
   on dark mode flashes near-invisible (#e8e8e8 on #ffd900 ≈ 1.13:1). */
@media (prefers-color-scheme: dark) {
  a:hover { color: #000; }
}

/* Meta-link surfaces */
.Navigation a,
.posts-navigation a,
.post-footer a,
.entry-meta a,
.Archive-meta a,
.Archive-readMore,
.entry-title a,
.Film-title a,
.Home-selectedNotes .archive-list a,
.Home-sectionMore a,
.RelatedPosts-list a {
  color: inherit;
  text-decoration: none;
  background: none;
  padding-bottom: 0.05em;
  border-bottom: 1px solid transparent;
}

.Navigation a:hover,
.posts-navigation a:hover,
.post-footer a:hover,
.entry-meta a:hover,
.Archive-meta a:hover,
.Archive-readMore:hover,
.entry-title a:hover,
.Film-title a:hover,
.Home-selectedNotes .archive-list a:hover,
.Home-sectionMore a:hover,
.RelatedPosts-list a:hover {
  color: var(--ink);
  background: none;
  text-decoration: none;
  border-bottom-color: var(--accent);
}

/* Image-only links: never decorate */
a:has(> img:only-child),
a:has(> img:only-child):hover {
  text-decoration: none;
  background: none;
  border-bottom-color: transparent;
}
a:has(> img:only-child):hover { opacity: 0.92; }

.Navigation li        { display: inline-block; margin-right: 0.6em; }
.NavItem::after       { content: "→"; color: var(--rule); }
.nav-next::after      { content: "→"; color: var(--muted); }
.nav-previous::before { content: "←"; color: var(--muted); }

.nav-previous,
.nav-next { display: inline-block; margin-right: 0.8em; }


/* ====================================================================
   5. Layout — narrow column with full-bleed figures
   ==================================================================== */

.Main {
  display: grid;
  grid-template-columns:
    [full-start] 1fr
    [main-start] min(var(--column), calc(100% - 2em)) [main-end]
                 1fr [full-end];
  max-width: 150em;
  margin-inline: auto;
  padding-block: var(--rhythm);
}

/* Single-post article and Films-page section wrappers are transparent
   to the grid so their children (figures, paragraphs, headings) become
   effective grid children of .Main and the column rules below apply.
   Archive-item articles are real grid containers (subgrid) and must
   be excluded.

   The .Film selector is for `<section class="Film">` blocks emitted
   by page-films.php — each film entry. Without display:contents the
   iframes inside get trapped at the section's natural width and
   legacy width="940" attributes overflow narrow viewports. */
.Main > article:not(.Archive-item),
.Main > section.Film { display: contents; }

.Main > *,
.Main > article > *,
.Main > section.Film > * { grid-column: main; }

/* Bleed: the canonical Tyler Sticka responsive pattern.
   Default (narrow): bleeding content is FULL-BLEED both sides.
   Wide  (>=60em):    bleeding content is HALF-BLEED (text-col-start
                      to right page edge) so a small text column
                      can sit beside it.
   Bleeding content includes: figures (single posts and archives),
   wpautop-wrapped images, iframes (bare or wrapped), and the
   ProjectCard image at narrow widths. The wide-viewport switch is
   declared once at the bottom of this file for ALL these classes
   together, so the rule never gets out of sync.                     */

.Main > figure,
.Main > article > figure,
.Main > section.Film > figure { grid-column: full-start / full-end; }

.Main > * + *,
.Main > article > * + *,
.Main > section.Film > * + * { margin-top: var(--rhythm); }

/* More breathing room around figures and embedded media */
.Main > figure,
.Main > article > figure,
.Main > section.Film > figure,
.Main > article > p:has(> img:only-child),
.Main > section.Film > p:has(> img:only-child),
.Main > article > p:has(> a:only-child > img:only-child),
.Main > section.Film > p:has(> a:only-child > img:only-child),
.Main > article > p:has(> iframe),
.Main > section.Film > p:has(> iframe),
.Main > article > div:has(> iframe),
.Main > section.Film > div:has(> iframe) {
  margin-block: calc(var(--rhythm) * 2);
}


/* -- Captioned figures -------------------------------------------------
   Tyler Sticka's named-column pattern, two-state responsive:

   - Narrow (< 60em): image full-bleed BOTH sides; caption tucks
     underneath in the main text column.
   - Wide  (≥ 60em): image half-bleed (text-col → right page edge);
     caption tucks into the left gutter, bottom-aligned with the image.

   Implementation note: figure uses `grid-template-columns: subgrid`
   so it adopts .Main's column tracks AND its named lines (full-start,
   main-start, main-end, full-end). Without subgrid, the named lines
   aren't defined inside the figure (article uses display:contents,
   which means CSS inheritance pulls from article — none — not from
   .Main) and the layout collapses with caption overlapping image.    */

:is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) {
  display: grid;
  grid-column: full-start / full-end;
  grid-template-columns: subgrid;
  margin-block: calc(var(--rhythm) * 2);
}

/* Narrow viewport: image full-bleed both sides, caption in main col
   on the row below. Sequential row flow handles the stacking. */
:is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > img,
:is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > a,
:is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > div,
:is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > iframe,
:is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > video      { grid-column: full-start / full-end; }
:is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > figcaption { grid-column: main; }

/* Wide viewport: side-by-side. Image on right (text-col → page edge),
   caption tucked into left gutter, bottom-aligned with the image. */
@media (min-width: 60em) {
  :is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) {
    align-items: end;
  }
  :is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > img,
  :is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > a,
  :is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > div,
  :is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > iframe,
  :is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > video {
    grid-column: main-start / full-end;
    grid-row: 1;
  }
  :is(.Main, .Main > article, .Main > section.Film) > figure:has(> figcaption) > figcaption {
    grid-column: full-start / main-start;
    grid-row: 1;
    padding-inline: 1em;
    align-self: end;
    text-align: right;
  }
}


/* -- Image sizing ----------------------------------------------------- */
:is(.Main, .Main > article, .Main > section.Film) > figure img,
:is(.Main, .Main > article, .Main > section.Film) > figure video,
:is(.Main, .Main > article, .Main > section.Film) > p     img { width: 100%; height: auto; display: block; }

:is(.Main, .Main > article, .Main > section.Film) > figure > div { width: 100%; }

/* wpautop wraps standalone images in <p> — full-bleed at narrow,
   half-bleed at wide via the responsive switch at the bottom. */
:is(.Main, .Main > article, .Main > section.Film) > p:has(> img:only-child),
:is(.Main, .Main > article, .Main > section.Film) > p:has(> a:only-child > img:only-child) {
  grid-column: full-start / full-end;
  margin-inline: 0;
}

/* Image-only link styling already declared in the Links section (~line 195). */


/* -- Video iframes ----------------------------------------------------
   Goal: every video right-bleeds (text-column-start to right page edge)
   regardless of how it was embedded. iframes get a paper background so
   they never flash white before the player loads. Native aspect ratio
   is respected when an explicit padding-wrapper is present (Vimeo's
   responsive embed encodes the ratio in the wrapper's padding-bottom);
   otherwise we default to 16:9.                                       */

iframe { background: var(--paper); color-scheme: dark light; }

/* Bare iframe (no wrapper): full-bleed at narrow, half-bleed at
   wide (via the responsive switch at the bottom of this file). */
:is(.Main, .Main > article, .Main > section.Film) > iframe {
  display: block;
  grid-column: full-start / full-end;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border: 0;
}

/* Iframe inside <p> (wpautop wraps embeds): bleed the <p>. */
:is(.Main, .Main > article, .Main > section.Film) > p:has(> iframe:only-child) {
  grid-column: full-start / full-end;
  margin-inline: 0;
}
:is(.Main, .Main > article, .Main > section.Film) > p > iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
  border: 0;
}

/* Iframe inside Vimeo's responsive padding wrapper: respect the
   wrapper's aspect ratio (encoded as padding-bottom percentage).
   Bleed the wrapper. Don't touch the iframe's positioning —
   it's correctly absolute-filled inside the wrapper. */
:is(.Main, .Main > article, .Main > section.Film) > div[style*="padding"][style*="position"],
:is(.Main, .Main > article, .Main > section.Film) > figure > div[style*="padding"][style*="position"] {
  grid-column: full-start / full-end;
  margin-inline: 0;
  width: 100%;
}

/* Captioned figures wrapping a padding-box: figure handles the
   right-bleed via the captioned-figure rules above. The padding
   wrapper inside fills the figure's image cell at the natural ratio. */
:is(.Main, .Main > article, .Main > section.Film) > figure > div[style*="padding"][style*="position"] > iframe {
  border: 0;
}

/* Loose <iframe> inside a <div> wrapper that ISN'T the padding hack
   (rare; some old embeds): bleed the div. Responsive switch below. */
:is(.Main, .Main > article, .Main > section.Film) > div:has(> iframe):not([style*="padding"]) {
  grid-column: full-start / full-end;
  margin-inline: 0;
}

/* Hide loose <script> wrappers that came with old embed code */
:is(.Main, .Main > article, .Main > section.Film) > p:has(> script:only-child) { display: none; }



/* ====================================================================
   6. Mobile tweaks
   ==================================================================== */

@media (max-width: 40em) {
  .entry-title { padding-top: 2em; }
  .Navigation a { display: inline-block; padding: 0.5em 0; }
}


/* ====================================================================
   7. Dark mode
   ==================================================================== */

@media (prefers-color-scheme: dark) {
  :root {
    --ink:         #e8e8e8;   /* primary body text on dark */
    --paper:       #111;      /* page background on dark */
    --muted:       #999;      /* secondary / meta text — always less
                                 prominent than --ink, in this mode
                                 that means closer to --paper        */
    --rule:        #333;
    --rule-light:  #2a2a2a;
  }
}


/* ====================================================================
   8. Meta material — date, taxonomy, posts-navigation, "Read more"
   Same Inter family, same body size as prose. Differentiated only
   by colour (--meta-color) and weight (--meta-weight). Never a
   different font, never a different size.
   ==================================================================== */

.Navigation {
  color: var(--meta-color);
  font-weight: var(--meta-weight);
}

.posts-navigation,
.post-footer,
.Archive-meta,
.Archive-readMore {
  color: var(--meta-color);
  font-weight: var(--meta-weight);
}

/* Post footer block — date on its own line; section + tags below.
   The big breathing room belongs HERE, between the article body
   and the meta (not between meta and the older/newer nav).
   Higher-specificity selector to beat .Main > article > * + *. */
.Main > article > .post-footer,
article .post-footer {
  margin-top: var(--section-break);
}
.post-footer-meta {
  margin-bottom: 0.5em;
}
.post-footer-tags {
  line-height: 1.6;
}

/* Older / Newer post nav — sits close to the meta, not far from it */
.posts-navigation {
  margin-top: 2em;
}

/* Related posts: a small editorial discovery block at the bottom of
   each single post, just above the older/newer nav. Visually a light
   list — date, title — using the same meta type role as the post
   footer. Appears only when the algorithm finds 1+ related posts. */
.RelatedPosts {
  grid-column: main;
  margin-top: var(--section-break);
  color: var(--meta-color);
}
.RelatedPosts-heading {
  font-size: 1em;
  font-weight: 700;
  color: var(--ink);
  padding-top: 0;
  margin-bottom: 1em;
}
.RelatedPosts-list { list-style: none; margin: 0; padding: 0; }
.RelatedPosts-list li {
  display: flex;
  flex-wrap: wrap;
  gap: 1em;
  align-items: baseline;
  padding: 0.5em 0;
  border-bottom: 1px solid var(--rule-light);
}
.RelatedPosts-list time { flex: 0 0 auto; min-width: 8em; color: var(--meta-color); }
.RelatedPosts-list a {
  text-decoration: none;
  background: none;
  color: inherit;
  border-bottom: 1px solid transparent;
  padding-bottom: 0.05em;
}
.RelatedPosts-list a:hover {
  background: none;
  border-bottom-color: var(--accent);
  color: var(--ink);
}
@media (max-width: 40em) {
  .RelatedPosts-list time { min-width: 6em; }
}


/* ====================================================================
   9. Footer
   ==================================================================== */

.Footer {
  color: var(--muted);
  margin-top: var(--section-break);
  margin-bottom: var(--section-break);
}

.screen-reader-text,
.nav-subtitle {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}

/* Skip-to-content link — first focusable element. Visually hidden
   until focused, then jumps to top-left with an accent background.
   Accessibility requirement: gives screen-reader and keyboard users
   a way to bypass the navigation. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 1000;
  padding: 0.6em 1em;
  background: var(--accent);
  color: var(--ink);
  text-decoration: none;
  font-weight: 700;
}
.skip-link:focus {
  left: 0;
  outline: 3px solid var(--ink);
  outline-offset: 2px;
}

/* Focus-visible: clear keyboard-only focus indicator using the
   accent colour. Mouse clicks don't trigger this; only Tab. */
:focus { outline: none; }
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}
/* Image-only links: ring around the image instead of opacity dip */
a:has(> img:only-child):focus-visible {
  outline-offset: -3px;
}


/* ====================================================================
   10. Archive pages — each item reads as a post
   Title (linked, same size as single-post .entry-title) -> optional
   image -> excerpt with inline "Read more" -> dated meta line below.
   No section header, no HRs, no archive-specific title size override.
   ==================================================================== */

.Archive-item {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
}
.Archive-item > * { grid-column: main; }

/* Featured image: full-bleed by default (narrow). Wide-viewport
   media query at the bottom switches to half-bleed. The
   .Archive-figureLink wraps the actual <figure>; the figure itself
   is never a direct child of .Archive-item, so we only target the
   link wrapper here. */
.Archive-item > .Archive-figureLink {
  grid-column: full-start / full-end;
}

.Archive-figureLink {
  display: block;
  margin-block: 1.5em;
}
.Archive-figureLink:hover { opacity: 0.92; }
.Archive-figure { margin: 0; }
.Archive-figure img {
  width: 100%;
  height: auto;
  display: block;
}

.Archive-excerpt { color: var(--ink); }

/* Inline "Read more" link injected at end of last excerpt paragraph.
   Explicit inheritance: this is inline-flow within a paragraph, so
   font-size, line-height, vertical-align must match the surrounding
   prose exactly. Without these, some browser/font combinations
   render the link slightly off-baseline. */
.Archive-readMore {
  white-space: nowrap;
  margin-left: 0.4em;
  font-size: inherit;
  font-family: inherit;
  line-height: inherit;
  vertical-align: baseline;
}
.Archive-readMore > span { font-size: inherit; vertical-align: baseline; }

/* Dated meta line at the foot of each archive item */
.Archive-meta { margin-top: 1.5em; }


/* ====================================================================
   11. Gutenberg block editor compatibility
   ==================================================================== */

.wp-block-image.alignleft,
.wp-block-image.alignright,
.wp-block-image.aligncenter {
  float: none;
  margin-left: 0;
  margin-right: 0;
}

@media (min-width: 60em) {
  :is(.Main, .Main > article, .Main > section.Film) > figure > a       { grid-column: main-start / full-end; display: block; }
  :is(.Main, .Main > article, .Main > section.Film) > figure > a > img { width: 100%; }
}

/* Gutenberg block defaults: full-bleed at narrow (Sticka switch
   below promotes them to half-bleed at >=60em). */
:is(.Main, .Main > article, .Main > section.Film) > .wp-block-gallery,
:is(.Main, .Main > article, .Main > section.Film) > .wp-block-embed,
:is(.Main, .Main > article, .Main > section.Film) > .wp-block-pullquote { grid-column: full-start / full-end; }


/* ====================================================================
   11a. Series — multi-image figures

       <figure class="Series" data-shape="triptych">      <!-- pair | triptych | grid | grid-4 | strip -->
         <div class="Series-images">
           <img>...                                       <!-- N bare imgs -->
           <figure><img><figcaption></figure>...          <!-- or per-image inner figures -->
         </div>
         <figcaption>Shared caption.</figcaption>         <!-- optional -->
       </figure>

   Outer figure rides the captioned-figure pattern (section 5): subgrid
   of .Main, full-bleed at narrow, half-bleed-right at >=60em with the
   shared caption right-aligned in the left rail. This section adds the
   inner image grid, per-image caption styling, and shape-driven column
   counts. Three breakpoints (<40em / 40-60em / >=60em). Per-figure
   overrides: --series-cols-{narrow,mid,wide}, --series-aspect: auto,
   data-bleed="full" (full-bleed both sides at all widths).
   ==================================================================== */

/* Shape defaults — column counts at narrow / mid / wide. */
.Series[data-shape="pair"]      { --series-cols-narrow: 2; --series-cols-mid: 2; --series-cols-wide: 2; }
.Series[data-shape="triptych"]  { --series-cols-narrow: 1; --series-cols-mid: 3; --series-cols-wide: 3; }
.Series[data-shape="grid"]      { --series-cols-narrow: 2; --series-cols-mid: 3; --series-cols-wide: 3; }
.Series[data-shape="grid-4"]    { --series-cols-narrow: 2; --series-cols-mid: 3; --series-cols-wide: 4; }
.Series[data-shape="strip"]     { --series-cols-narrow: 2; --series-cols-mid: 4; --series-cols-wide: 6; }

/* Resolve --series-cols per breakpoint. Fallbacks 2/3/3 when no shape. */
.Series                    { --series-cols: var(--series-cols-narrow, 2); }
@media (min-width: 40em) {
  .Series                  { --series-cols: var(--series-cols-mid,    3); }
}
@media (min-width: 60em) {
  .Series                  { --series-cols: var(--series-cols-wide,   3); }
}

/* Outer figure — subgrid shell of .Main (mirrors section 5). */
:is(.Main, .Main > article, .Main > section.Film) > figure.Series {
  display: grid;
  grid-column: full-start / full-end;
  grid-template-columns: subgrid;
  margin-block: calc(var(--rhythm) * 2);
  align-items: start;                              /* M-B grid: shared caption top-aligns with image grid */
}

/* Inner image grid — fills the bleed cell. */
.Series > .Series-images {
  display: grid;
  grid-template-columns: repeat(var(--series-cols, 2), 1fr);
  gap: var(--series-gap);
  grid-column: full-start / full-end;
}

/* Per-image-captioned grids: roomier rows + 1em inset so the leftmost
   caption doesn't butt the screen edge. Inset is dropped at >=60em
   where the image area already starts at main-start. */
.Series:has(> .Series-images > figure) > .Series-images {
  row-gap: var(--series-row-gap);
  padding-inline: var(--rhythm);
}

/* Image cells — uniform 3:2 crop (--series-aspect: auto opts out). */
.Series > .Series-images > img,
.Series > .Series-images > figure > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: var(--series-aspect, 3 / 2);
}

/* Per-image inner figure — image stacked above caption. */
.Series > .Series-images > figure {
  margin: 0;
  display: grid;
  grid-template-rows: auto auto;
  gap: 0.4em;
}
.Series > .Series-images > figure > figcaption {
  padding-top: 0;                                  /* spacing handled by parent gap */
  font-size: var(--series-cap-size);
  line-height: 1.35;
  font-variant-numeric: tabular-nums;              /* timestamps align */
}

/* Shared figcaption — breathing room above when it tucks under at narrow. */
.Series > figcaption { padding-top: 1em; }

/* Wide viewport (>=60em) — half-bleed-right by default, with explicit
   layout-inline and layout-full-bleed overrides matching Image / Embed.
   Shared caption sits at the TOP of the left rail (align-self: start) —
   Müller-Brockmann grid: caption pinned to the same baseline as the
   first image row, not vertically centered or bottom-aligned. */
@media (min-width: 60em) {

  /* ---- Default (.layout-half-bleed): right-bleed image area, caption
          in left rail, top-aligned, right-aligned text. -------------- */
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series > .Series-images {
    grid-column: main-start / full-end;
    grid-row: 1;
  }
  /* Per-image-cap inset is redundant at wide (main-start already insets). */
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series:not(.layout-full-bleed):not([data-bleed="full"]):has(> .Series-images > figure) > .Series-images {
    padding-inline: 0;
  }
  /* Override §5's bottom-align — Series captions go to the TOP of the
     rail. Higher specificity than §5 (extra .Series class) so it wins. */
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series {
    align-items: start;
  }
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series > figcaption {
    padding-top: 0;
    align-self: start;
  }

  /* ---- .layout-full-bleed (or legacy data-bleed="full") — image area
          stays full-bleed; shared caption drops under in main col.    */
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series.layout-full-bleed > .Series-images,
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series[data-bleed="full"] > .Series-images {
    grid-column: full-start / full-end;
  }
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series.layout-full-bleed > figcaption,
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series[data-bleed="full"] > figcaption {
    grid-column: main;
    grid-row: auto;
    align-self: auto;
    text-align: left;
    padding-inline: 0;
    padding-top: 1em;
  }

  /* ---- .layout-inline — image grid stays in the main reading column
          at every viewport, caption tucks underneath. Mirror of §14
          for single-figure embeds, applied to the multi-image case. */
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series.layout-inline > .Series-images {
    grid-column: main;
    grid-row: auto;
  }
  :is(.Main, .Main > article, .Main > section.Film) > figure.Series.layout-inline > figcaption {
    grid-column: main;
    grid-row: auto;
    align-self: auto;
    text-align: left;
    padding-inline: 0;
    padding-top: 1em;
  }
}

/* Inline layout at every viewport — outer figure stays in main col,
   not full-bleed. Defined outside the media query so it applies at
   narrow too (where the default .Series figure would be full-bleed). */
:is(.Main, .Main > article, .Main > section.Film) > figure.Series.layout-inline {
  grid-column: main;
}
:is(.Main, .Main > article, .Main > section.Film) > figure.Series.layout-inline > .Series-images {
  grid-column: main;
}


/* ====================================================================
   11b. Body-of-work label — small muted year-line above an h2

   Used on photography sub-pages and any other "body of work" page to
   sit a year-range / status line above the h2. Pattern:

       <p class="BodyLabel">Body of work, 2005 – ongoing</p>
       <h2>People using phones</h2>

   Spec: 00-source-of-truth/body-of-work-pattern.md
   ==================================================================== */

/* Specificity matches the theme's .Main > article > * + * rhythm rule
   (section 5) so margin-top: 4em wins. */
:is(.Main, .Main > article, .Main > section.Film) > .BodyLabel {
  color: var(--muted);
  font-weight: 700;
  margin-top: 4em;
}
.BodyLabel + h2 { padding-top: 0.2em; }   /* tighten the gap so label + h2 read as a pair */


/* ====================================================================
   12. Home (About) — selected work + selected writing
   Sections injected via [selected_work] and [selected_writing]
   shortcodes inside the About page content. Right-bleed the
   container, image-forward project cards, dated archive list for
   writing.
   ==================================================================== */

/* Default (narrow): flatten the section/ul/li/anchor hierarchy with
   display:contents so each piece becomes a direct grid child of
   .Main. Text elements end up in the main column; only the
   ProjectCard image escapes to full-bleed. Same flatten trick as
   the Projects archive. */
.Home-selectedWork,
.Home-selectedWork .ProjectCards,
.Home-selectedWork .ProjectCard,
.Home-selectedWork .ProjectCard > a,
.Home-selectedNotes,
.Home-selectedNotes .archive-list {
  display: contents;
}

/* Section heading and "All ..." footer link sit in main column. */
.Home-sectionLabel {
  grid-column: main;
  font-size: 1em;
  font-weight: 700;
  color: var(--muted);
  margin-top: calc(var(--rhythm) * 3);
  margin-bottom: 1em;
  padding-top: 0;
}
.Home-sectionMore {
  grid-column: main;
  margin-top: 1em;
  color: var(--meta-color);
}
.Home-sectionMore a {
  text-decoration: none;
  background: none;
  border-bottom: 1px solid transparent;
  padding-bottom: 0.05em;
}
.Home-sectionMore a:hover {
  background: none;
  border-bottom-color: var(--accent);
  color: var(--ink);
}

/* Project card pieces. Image: full-bleed at narrow (half-bleed at
   wide via Sticka switch). Title/year: main column. */
.ProjectCard-image {
  grid-column: full-start / full-end;
  width: 100%;
  height: auto;
  aspect-ratio: auto;
  object-fit: initial;
  display: block;
  background: var(--rule-light);
  margin-block: 0.5em;
  transition: opacity 0.25s;
}
.ProjectCard a:hover .ProjectCard-image { opacity: 0.92; }
.ProjectCard-title {
  grid-column: main;
  display: block;
  font-weight: 700;
  font-size: 1em;
  margin-top: 0.5em;
  padding-top: 0;
  letter-spacing: -0.005em;
}
.ProjectCard-year {
  grid-column: main;
  display: block;
  color: var(--meta-color);
  margin-top: 0.1em;
  margin-bottom: 1.5em;
  font-size: 1em;
}
.ProjectCard a {
  color: inherit;
  text-decoration: none;
  background: none;
  border-bottom: none;
}

/* Selected writing list items: each li in main column, dated row. */
.Home-selectedNotes .archive-list li {
  grid-column: main;
  display: flex;
  gap: 1em;
  padding: 0.5em 0;
  border-bottom: 1px solid var(--rule-light);
  align-items: baseline;
  flex-wrap: wrap;
}
.Home-selectedNotes .archive-list time {
  flex: 0 0 auto;
  color: var(--meta-color);
  min-width: 8em;
}
.Home-selectedNotes .archive-list a {
  text-decoration: none;
  background: none;
  color: inherit;
  border-bottom: 1px solid transparent;
  padding-bottom: 0.05em;
}
.Home-selectedNotes .archive-list a:hover {
  background: none;
  border-bottom-color: var(--accent);
}

/* Wide (>=60em): restore the 2-col card grid for Selected work.
   The section becomes a real grid container again, sized at the
   half-bleed band; cards arrange themselves inside. */
@media (min-width: 60em) {
  .Home-selectedWork {
    display: block;
    grid-column: main-start / full-end;
    margin-block: calc(var(--rhythm) * 3);
  }
  .Home-selectedWork .ProjectCards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20em, 1fr));
    gap: 2em;
    list-style: none;
    margin: 0; padding: 0;
  }
  .Home-selectedWork .ProjectCard,
  .Home-selectedWork .ProjectCard > a {
    display: block;
  }
  .Home-selectedWork .ProjectCard a { display: block; }
  .Home-selectedWork .ProjectCard-image {
    grid-column: auto;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    margin-block: 0;
  }
  .Home-selectedWork .ProjectCard-title  { grid-column: auto; margin-top: 0.6em; }
  .Home-selectedWork .ProjectCard-year   { grid-column: auto; margin-bottom: 0; }
  .Home-selectedWork .Home-sectionLabel,
  .Home-selectedWork .Home-sectionMore   { grid-column: auto; margin-top: 0; margin-bottom: 1.5em; }
  .Home-selectedWork .Home-sectionMore   { margin-top: 1.5em; margin-bottom: 0; }

  /* Selected writing: section back as block, list back as a normal
     ul; items remain flex rows. */
  .Home-selectedNotes {
    display: block;
    grid-column: main;
    margin-block: calc(var(--rhythm) * 3);
  }
  .Home-selectedNotes .archive-list {
    display: block;
    list-style: none;
    margin: 0; padding: 0;
  }
  .Home-selectedNotes .archive-list li { grid-column: auto; }
  .Home-selectedNotes .Home-sectionLabel,
  .Home-selectedNotes .Home-sectionMore { grid-column: auto; margin-top: 0; }
  .Home-selectedNotes .Home-sectionMore  { margin-top: 1.5em; }
}

@media (max-width: 40em) {
  .Home-selectedNotes .archive-list time { min-width: 6em; }
}

/* Full Projects archive — two layouts switched at 60em.
   Wide:    image-forward 2-col card grid, half-bleed container.
   Narrow:  editorial stack — text in main column, image half-bleed
            right. Same visual language as single posts and writing
            archives. */

/* Excerpt color is the same body colour at all viewports — never
   muted, never different between breakpoints. */
.ProjectCards--full .ProjectCard-excerpt {
  display: block;
  color: var(--ink);
  font-size: 1em;
  margin-top: 0.4em;
  line-height: 1.45;
}

/* Wide (>=60em): real grid container with uniform 3:2 card images. */
@media (min-width: 60em) {
  .ProjectCards--full {
    display: grid;
    grid-column: full-start / full-end;
    grid-template-columns: repeat(auto-fit, minmax(24em, 1fr));
    gap: 2.5em 2em;
    margin-top: 2em;
    list-style: none;
    padding: 0;
  }
  .ProjectCards--full > .ProjectCard {
    list-style: none;
    display: block;
  }
  .ProjectCards--full > .ProjectCard > a {
    display: block;
    color: inherit;
    text-decoration: none;
    background: none;
    border-bottom: none;
  }
  .ProjectCards--full > .ProjectCard > a:hover .ProjectCard-image { opacity: 0.92; }
  .ProjectCards--full .ProjectCard-image {
    aspect-ratio: 3 / 2;
    object-fit: cover;
    margin-block: 0;
  }
  .ProjectCards--full .ProjectCard-title  { margin-top: 0.6em; padding-top: 0; }
  .ProjectCards--full .ProjectCard-year   { margin-bottom: 0; }
}

/* Narrow — flatten the card structure (display:contents on
   .ProjectCards, each .ProjectCard, and the inner anchor) so the
   image and text become direct grid children of .Main and inherit
   the exact same layout rules that govern single-post content. */
@media (max-width: 60em) {
  .ProjectCards--full,
  .ProjectCards--full > .ProjectCard,
  .ProjectCards--full > .ProjectCard > a {
    display: contents;
  }

  /* Image: full-bleed both sides at narrow viewports — same as
     a single-post figure. The responsive switch at the bottom of
     this file handles the >=60em case (but at >=60em this whole
     narrow block is replaced by the 2-col card grid). */
  .ProjectCards--full .ProjectCard-image {
    grid-column: full-start / full-end;
    width: 100%;
    height: auto;
    aspect-ratio: auto;
    object-fit: initial;
    display: block;
    /* Big breathing room above each project's image — separates it
       from the previous project's excerpt. */
    margin-block: calc(var(--rhythm) * 5) calc(var(--rhythm) * 2);
  }

  /* First card has less top margin on its image (no preceding project) */
  .ProjectCards--full > .ProjectCard:first-child > a > .ProjectCard-image {
    margin-top: calc(var(--rhythm) * 2);
  }

  /* Title: heading inside main column. Same h2 styling. */
  .ProjectCards--full .ProjectCard-title {
    grid-column: main;
    font-size: 1em;
    font-weight: 700;
    padding-top: 0;
    margin-top: 0;
    line-height: 1.3;
  }
  .ProjectCards--full .ProjectCard-year {
    grid-column: main;
    color: var(--meta-color);
    margin-top: 0.2em;
    padding-top: 0;
  }
  .ProjectCards--full .ProjectCard-excerpt {
    grid-column: main;
    color: var(--ink);
    margin-top: 0.8em;
  }

  /* Anchor styling: still no underline since the whole block is a link */
  .ProjectCards--full > .ProjectCard > a {
    color: inherit;
    text-decoration: none;
    background: none;
    border-bottom: none;
  }
  .ProjectCards--full > .ProjectCard > a:hover .ProjectCard-image { opacity: 0.92; }
  .ProjectCards--full > .ProjectCard > a:hover .ProjectCard-title { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: var(--underline); text-underline-offset: var(--underline-offset); }
}


/* ====================================================================
   13. The Sticka switch — bleed responsive
   This is THE central pattern. Default = full-bleed both sides
   (narrow viewports). At >=60em, every bleeding element switches
   to half-bleed (text-col-start to right page edge), so the
   text column can sit beside it. Captioned figures already
   include their own responsive switch above; this rule covers
   everything else.

   Do not change individual rules above to be half-bleed by
   default — keep all defaults full-bleed and let this one
   block be the source of truth for the wide-viewport override.
   ==================================================================== */

@media (min-width: 60em) {
  .Main > figure,
  .Main > article > figure,
  .Main > section.Film > figure,
  :is(.Main, .Main > article, .Main > section.Film) > p:has(> img:only-child),
  :is(.Main, .Main > article, .Main > section.Film) > p:has(> a:only-child > img:only-child),
  :is(.Main, .Main > article, .Main > section.Film) > p:has(> iframe:only-child),
  :is(.Main, .Main > article, .Main > section.Film) > div:has(> iframe):not([style*="padding"]),
  :is(.Main, .Main > article, .Main > section.Film) > div[style*="padding"][style*="position"],
  :is(.Main, .Main > article, .Main > section.Film) > figure > div[style*="padding"][style*="position"],
  :is(.Main, .Main > article, .Main > section.Film) > iframe,
  .Archive-item > .Archive-figureLink,
  .ProjectCards--full,
  :is(.Main, .Main > article, .Main > section.Film) > .wp-block-gallery,
  :is(.Main, .Main > article, .Main > section.Film) > .wp-block-embed,
  :is(.Main, .Main > article, .Main > section.Film) > .wp-block-pullquote {
    grid-column: main-start / full-end;
  }
  /* .Home-selectedWork and .Home-selectedNotes handle their own
     wide-viewport behaviour in the Home section above (they exit
     display:contents and become normal grid items in main column). */
}


/* ====================================================================
   14. Embed blocks — block-editor layout switches

   Site-specific layer on top of the captioned-figure pattern (§5).
   The block editor in src/blocks/Embed.astro emits a <figure> with
   one of three layout classes (.layout-inline, .layout-half-bleed,
   .layout-full-bleed) and a `--aspect` custom property, optionally
   capped by max-width. This section honours those signals.

   Half-bleed is the default and uses the theme's captioned-figure
   pattern unchanged — no rule needed here.

   Not yet ported back to 06-theme/elastic-26/style.css; if WP
   gets a similar block convention, mirror these rules across.
   ==================================================================== */

/* Apply the figure's --aspect to its iframe / embed-host so the
   author's declared ratio is honoured regardless of layout class.
   Without this the iframe falls back to its 300×150 default. */
:is(.Main, .Main > article, .Main > section.Film) > figure[style*="--aspect"] > iframe,
:is(.Main, .Main > article, .Main > section.Film) > figure[style*="--aspect"] > .embed-host {
  display: block;
  width: 100%;
  aspect-ratio: var(--aspect);
  border: 0;
}

/* Inline layout: figure stays inside the main reading column at every
   viewport width. Left-aligned with the prose (margin-inline: 0) so a
   sub-column-width embed sits flush with the text rather than floating
   centered, matching the editorial language of the rest of the site.
   Override the captioned-figure subgrid (§5) — match its selector
   specificity so we don't need !important. */
:is(.Main, .Main > article, .Main > section.Film) > figure.layout-inline:has(> figcaption),
:is(.Main, .Main > article, .Main > section.Film) > figure.layout-inline {
  display: block;
  grid-column: main;
  margin-inline: 0;
  align-items: initial;
}
:is(.Main, .Main > article, .Main > section.Film) > figure.layout-inline > iframe,
:is(.Main, .Main > article, .Main > section.Film) > figure.layout-inline > .embed-host,
:is(.Main, .Main > article, .Main > section.Film) > figure.layout-inline > figcaption {
  grid-column: auto;
}
/* At wide viewports the captioned-figure rule (§5) tries to bottom-align
   the figure's children — block layout doesn't honour align-items, but
   reset it explicitly so a future grid-mode override doesn't surprise. */
@media (min-width: 60em) {
  :is(.Main, .Main > article, .Main > section.Film) > figure.layout-inline:has(> figcaption) > iframe,
  :is(.Main, .Main > article, .Main > section.Film) > figure.layout-inline:has(> figcaption) > .embed-host {
    grid-column: auto;
    grid-row: auto;
  }
  :is(.Main, .Main > article, .Main > section.Film) > figure.layout-inline:has(> figcaption) > figcaption {
    grid-column: auto;
    grid-row: auto;
    padding-inline: 0;
    text-align: left;
    align-self: auto;
  }
}

/* Full-bleed layout: stays full-bleed at all widths, including the
   wide breakpoint where the Sticka switch (§13) would otherwise pull
   it into half-bleed. Caption tucks underneath in main col. */
@media (min-width: 60em) {
  :is(.Main, .Main > article, .Main > section.Film) > figure.layout-full-bleed,
  :is(.Main, .Main > article, .Main > section.Film) > figure.layout-full-bleed:has(> figcaption) {
    grid-column: full-start / full-end;
  }
  :is(.Main, .Main > article, .Main > section.Film) > figure.layout-full-bleed:has(> figcaption) > iframe,
  :is(.Main, .Main > article, .Main > section.Film) > figure.layout-full-bleed:has(> figcaption) > .embed-host {
    grid-column: full-start / full-end;
    grid-row: auto;
  }
  :is(.Main, .Main > article, .Main > section.Film) > figure.layout-full-bleed:has(> figcaption) > figcaption {
    grid-column: main;
    grid-row: auto;
    padding-inline: 0;
    text-align: left;
    align-self: auto;
  }
}
