/*
** deck-enhancements.css
** Theme-agnostic structural rules — load AFTER deck.css, BEFORE any theme:
**
**   <link rel="stylesheet" href="deck.css" />
**   <link rel="stylesheet" href="deck-enhancements.css" />
**   <link rel="stylesheet" href="deck-byu-theme.css" />
**
** Extends deck.css's slide-grid engine with layout patterns deck.css
** doesn't provide (figure+text columns, side-by-side columns, a citation
** footer, an optional data-footer label) without hard-coding any theme's
** colors or fonts, so a different theme file can be swapped in without
** rebuilding any of this geometry.
*/

/* Hides the scrollbar when the source's <title data-noscroll> is set. */
html:has(title[data-noscroll]) article {
    scrollbar-width: none;
}
html:has(title[data-noscroll]) article::-webkit-scrollbar {
    display: none;
}

/* ─── Optional data-footer attribute: geometry half ──────────────────────
   Add data-footer="Your Name · Talk Title" to any <section> to show a
   footer label at bottom-left. deck.css does not define this at all.
   Theme sets the label's color. */
section::after {
    content: attr(data-footer);
    position: absolute;
    inset-block-end: 1.8vh;
    inset-inline-start: 1.5vw;
    font-size: 2.0vmin;
    line-height: 1;
}

/* ─── Title slide spacing ────────────────────────────────────────────────
   deck.css zeroes all margins on title slide children; restore spacing
   so the rule under the h1 is visually separated from the subtitle. */
section:first-of-type > * { margin-bottom: 1.2vh; }
section:first-of-type > :last-child { margin-bottom: 0; }

/* Guarantee a minimum gap below every content-slide title, regardless of
   layout — deck.css and the figure-grid rules both force the title's own
   margin-bottom to 0 and rely on centering tricks (auto margins, grid
   row-gap) to create space instead, which can collapse to nothing when
   there isn't enough slack. This applies everywhere instead of patching
   each layout separately. */
section:nth-of-type(n+2) > h1:first-child,
section:nth-of-type(n+2) > h2:first-child {
    margin-bottom: 1vh;
}

/* ─── Simple side-by-side columns ───────────────────────────────────────
   Wrap two or more elements in a container with class="cols" to lay them
   out as equal-width columns instead of stacking vertically — e.g. two
   short labeled lists (Positives/Negatives) that would otherwise take up
   more vertical space than they need. Only side-by-side in landscape;
   in portrait there isn't width to spare, so it stays stacked. */
.cols {
    display: flex;
    flex-direction: column;
    gap: 1vh;
}

.cols > * {
    flex: 1 1 0;
    min-width: 0;
}

@media (orientation: landscape) {
    .cols {
        flex-direction: row;
        gap: 3vw;
    }
}

/* ─── Two-column lists: one <ul> split visually into two columns ────────
   Some lists are just too tall for one column but aren't two separately
   labeled lists (contrast .cols, e.g. Positives/Negatives), so splitting
   them into two <div><ul> siblings read as more disconnected than they
   are and duplicated markup for no semantic reason. CSS multi-column
   layout keeps it one <ul> — items flow down column 1, then continue at
   the top of column 2. Landscape-only, same reasoning as .cols. */
@media (orientation: landscape) {
    .two-col > ul {
        column-count: 2;
        column-gap: 3vw;
    }
}

.two-col > ul > li {
    break-inside: avoid;
}

/* ─── Lists: marker geometry ─────────────────────────────────────────────
   deck.css uses padding-left: 4vw on ul, but most slides here are list-only
   (title directly followed by a ul, no lead-in paragraph), so that indent
   just shifts the whole body block rightward relative to the title instead
   of reading as a sub-list cue. The marker itself already signals "this is
   a list", so we flush it left and let the li's own padding carry the
   marker-to-text spacing instead. Theme sets the marker color. */
/* Browsers apply margin-block-start/-end: 1em to ul/ol by default. deck.css's
   `section > * { margin: 0 0 2vh }` only overrides this when the list is a
   direct child of <section> — inside a wrapping <div> (the figure+text
   layout) it's untouched. Zero it here so behavior is consistent everywhere,
   and so adjacent-sibling margin collapsing doesn't silently let this 1em
   default win over the tighter p-then-list spacing below. */
ul, ol { margin-block-start: 0; }

ul { padding-left: 0; list-style-type: none; }

/* When a paragraph directly introduces a list, tighten the gap between them
   so the list reads as elaborating on that paragraph rather than as a new,
   unrelated block. Also matches a paragraph followed by .two-col, since
   there the ul is wrapped a level down rather than being the direct
   sibling — same "introduces the list" relationship either way. */
p:has(+ ul),
p:has(+ ol),
p:has(+ .two-col) {
    margin-bottom: 0.8vh;
}

ul > li {
    padding-left: 2.4vmin;
    position: relative;
}

ul > li::before {
    content: '-';   /* hyphen-minus; theme sets the color */
    position: absolute;
    left: 0;
    width: 1.6vmin;
}

ul > li > ul { list-style-type: none; }

ul > li > ul > li::before {
    content: '-';   /* same marker, smaller for the sub-level */
    transform: scale(0.75);
    transform-origin: left center;
}

/* ─── Section-divider slides (lone h1 or h2) ────────────────────────────
   Any content slide with only a single heading renders as a full-bleed,
   centered section break. Theme sets its background/text colors. No
   classes needed. */
section:nth-of-type(n+2):has(> h1:only-child),
section:nth-of-type(n+2):has(> h2:only-child) {
    display: grid;
    place-content: center;
    text-align: center;
}

section:nth-of-type(n+2):has(> h1:only-child) h1,
section:nth-of-type(n+2):has(> h2:only-child) h2 {
    font-size: 1.6em;
}

/* ─── Blockquotes & citations: geometry ───────────────────────────────────
   <cite> after a blockquote: close the gap and match blockquote indentation.
   deck.css gives non-first section children margin-inline: 2.5vw, and the
   blockquote itself gets padding-left from deck.css's blockquote rule.
   The p wrapping cite needs to mirror that so the dash aligns with the quote. */
blockquote {
    margin: 0;  /* zero browser default margins (40px left/right, 1em top/bottom) */
}

blockquote + p {
    margin-top: 0;
    margin-bottom: 0;
    margin-inline: 2.5vw;
    padding-left: 0.75vw; /* align with blockquote border-left inset */
}

/* On the default figure grid, margin-inline is already zeroed on all
   non-figure children, so match that and rely only on the padding to align
   with the blockquote. */
section:nth-of-type(n+2):has(> figure):not(:has(> figure.fig-full, > figure.fig-solo, > figure.fig-top)) blockquote + p {
    margin-inline: 0;
    padding-left: 0.75vw;
}

cite { display: block; }

figcaption {
    text-align: center;
    line-height: 1.4;
}

figcaption cite {
    display: block;
    margin-top: 0.4vh;
    word-break: break-all;  /* long URLs won't overflow the figure column */
}

/* ─── Citation footer ─────────────────────────────────────────────────────
   Wrap a slide-ending <cite> in <footer> to pin it to the bottom of the
   slide, full width, instead of trailing as the last line of a content
   column or list.

     ...last bullet or paragraph...

     <footer>
     <cite>Author. Title. Venue, Year.</cite>
     </footer>

   In normal flow, not position: absolute, so the content above shrinks to
   fit rather than the footer floating over it. Grid slides: explicit
   third row. Flex slides: margin-top: auto pins it to the bottom. */
section:nth-of-type(n+2) > footer:last-child {
    grid-column: 1 / -1;
    grid-row: 3;
    flex: 0 0 auto;
    /* Clears deck.css's page-number badge (inset-block-end: 1vh + padding:
       1.5vh + font-size: 3vmin) — taller than the data-footer label, so it's
       the binding constraint. Also overrides the otherwise-auto default. */
    margin-bottom: calc(4vh + 3vmin);
    padding-top: 1vh;
}

/* Plain (non-figure) slides only: deck.css centers the body by splitting
   leftover space between margin-top: auto on the 2nd child and
   margin-bottom: auto on the last child. With a footer added, the 2nd
   child is no longer last, so it loses that half — add it back here to
   keep the body centered above the footer. */
section:nth-of-type(n+2):not(:has(> figure)):has(> footer) > :nth-child(2):not(footer) {
    margin-bottom: auto;
}

/* ─── Figure + text grid layout ─────────────────────────────────────────────
   Any content slide containing a <figure> gets a two-column layout.

   Source structure:

     # Slide Title

     <figure>
     <img src="photo.jpg" alt="…" />
     <figcaption>Caption</figcaption>
     </figure>
     <div>

     Content (blockquote, ul, ol, p, ...) goes here.

     </div>

   The wrapping <div> around the content is required, not optional: without
   it, each top-level content element (a p, a ul, ...) becomes its own grid
   item and is auto-placed into its own row, splitting the column's height
   evenly between them via grid-auto-rows: 1fr instead of letting them flow
   together as one block. Wrapping them in a single <div> keeps them as one
   grid item, so they lay out normally (in-flow) within the space the grid
   gives that item.

   For image on the right, add class="fig-right" to <figure>.

   Approach: explicit grid-column/grid-row on the figure pin it to
   column 1 across all content rows. The title spans both columns in
   row 1 via grid-column. The content div auto-places into column 2.
*/

section:nth-of-type(n+2):has(> figure) {
    display: grid;
    grid-template-columns: 1fr 1.8fr;
    /* title / content (fills remainder) / optional footer */
    grid-template-rows: auto 1fr auto;
    column-gap: 5vw;
    row-gap: 0;
    align-content: stretch;
    /* Cancel deck.css flex centring margins on this slide type */
    justify-content: start;
}

/* Cancel deck.css auto-margin flex-centring trick for the default figure
   grid only — fig-full/fig-solo/fig-top manage their own margins and flex
   behavior, so they're excluded here rather than fought with !important.
   footer excluded too: it needs its own margin-top: auto to reach the
   bottom row. */
section:nth-of-type(n+2):has(> figure):not(:has(> figure.fig-full, > figure.fig-solo, > figure.fig-top)) > :not(footer) {
    margin-top: 0;
    flex: none;
}

/* margin-bottom: 0 specifically on non-title children (figure, content) —
   kept separate from the rule above so it never competes with the title's
   own margin-bottom, which is governed solely by the universal heading
   rule above. Without this, deck.css's :last-child { margin-bottom: auto }
   wins for the content column, and being asymmetric with margin-top: 0,
   it pushes content to the top of its grid row instead of centering it. */
section:nth-of-type(n+2):has(> figure):not(:has(> figure.fig-full, > figure.fig-solo, > figure.fig-top)) > :not(:first-child):not(footer) {
    margin-bottom: 0;
}

/* Title: span both columns, row 1 */
section:nth-of-type(n+2):has(> figure) > :first-child {
    grid-column: 1 / -1;
    grid-row: 1;
    align-self: start;
    width: 100%;
}

/* Figure: column 1, content row */
section:nth-of-type(n+2):has(> figure) > figure {
    grid-column: 1;
    grid-row: 2;
    margin: 0;
    margin-inline: 0;
    align-self: center;   /* centre within the spanned rows */
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 1vh;
}

/* All other children (excluding a trailing citation footer — see above):
   auto-placed into successive rows from row 2, column assignment and
   gap-facing margin set separately below for the default (figure-left) vs
   fig-right (figure-right) case. Scoped away from fig-full/fig-solo/fig-top
   — without this, this rule's margin-inline ties in specificity with each
   variant's own margin-inline rule and only wins by accident of file
   order, e.g. a past bug where fig-top's text sat closer to the edge than
   every other slide. */
section:nth-of-type(n+2):has(> figure):not(:has(> figure.fig-full, > figure.fig-solo, > figure.fig-top)) > :not(:first-child):not(figure):not(footer) {
    align-self: center;
    min-width: 0;        /* prevent grid item from overflowing its column */
    overflow-wrap: break-word;
}

/* Default (figure on the left): content in column 2. Zero only the
   gap-facing (left) margin — the column-gap already provides that space.
   The outer (right) edge is left alone, so deck.css's own
   margin-inline: 2.5vw applies there, matching every other slide, instead
   of the separately-invented padding-right: 2vw this used to have.
   Excludes fig-right, which gets its own mirrored treatment below. */
section:nth-of-type(n+2):has(> figure):not(:has(> figure.fig-full, > figure.fig-solo, > figure.fig-top, > figure.fig-right)) > :not(:first-child):not(figure):not(footer) {
    grid-column: 2;
    margin-inline-start: 0;
}

section:nth-of-type(n+2):has(> figure) figure img {
    width: 100%;
    max-height: 65vh;
    object-fit: contain;
    padding: 0;
}

/* Emoji used in place of a photo/illustration inside a figure — sized to
   read at a glance from the back of a room, matching the visual weight a
   photo would have in the same slot. */
.emoji-figure {
    font-size: 25vmin;
    line-height: 1;
    cursor: default;
}

/* fig-right: figure goes to column 2, content to column 1 */
section:nth-of-type(n+2):has(> figure.fig-right) {
    grid-template-columns: 1.8fr 1fr;
}

section:nth-of-type(n+2):has(> figure.fig-right) > figure {
    grid-column: 2;
}

/* fig-right's content sits in column 1, so its gap-facing side is now the
   right edge (mirrored from the default case) — zero only that margin.
   The outer (left) edge is left alone entirely, so deck.css's own
   margin-inline: 2.5vw applies there, same as every other slide. */
section:nth-of-type(n+2):has(> figure.fig-right) > :not(:first-child):not(figure.fig-right):not(footer) {
    grid-column: 1;
    margin-inline-end: 0;
}

/* ─── Full-bleed figure background ──────────────────────────────────────
   For a hero/mood image that fills the entire slide as a backdrop, add
   class="fig-full" to the <figure>. All other slide content overlays on
   top of a dark scrim (figure::after) plus a text-shadow halo, so it
   stays legible no matter what's behind it in the photo. The halo's dark
   rgba(0,0,0,…) values are a theme-agnostic default that works over any
   photo backdrop regardless of palette, so they live here rather than in
   the theme file — otherwise every new theme would be forced to redefine
   them just to keep fig-full legible. Only the scrim's background color
   is theme-tunable, in deck-byu-theme.css.

     # Slide Title

     <figure class="fig-full">
     <img src="photo.jpg" alt="…" />
     </figure>

     Any number of content children follow and render on top of the image.
*/

/* Title slide keeps its original centered layout; content slides keep
   their title-top, body-below flow — only the figure becomes a backdrop. */
section:first-of-type:has(> figure.fig-full) {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    padding: 0;
    overflow: hidden;
}

section:nth-of-type(n+2):has(> figure.fig-full) {
    display: block;
    padding: 0;
    overflow: hidden;
}

section:has(> figure.fig-full) > figure.fig-full {
    position: absolute;
    inset: 0;
    margin: 0;
    z-index: 0;
    overflow: hidden;
}

section:has(> figure.fig-full) > figure.fig-full img {
    width: 100%;
    height: 100%;
    max-height: none;
    object-fit: cover;
    padding: 0;
}

/* Scrim geometry — theme sets the actual background color. */
section:has(> figure.fig-full) > figure.fig-full::after {
    content: '';
    position: absolute;
    inset: 0;
}

section:has(> figure.fig-full) > :not(figure) {
    position: relative;
    z-index: 1;
    margin-inline: 2.5vw;
    text-shadow:
        0 1px 2px rgba(0, 0, 0, 0.95),
        0 0 10px rgba(0, 0, 0, 0.85),
        0 0 28px rgba(0, 0, 0, 0.6);
}

section:has(> figure.fig-full) > :first-child {
    padding-top: 2vh;
}

section:has(> figure.fig-full) > :last-child {
    padding-bottom: 2vh;
}

/* ─── Full-width solo figure ─────────────────────────────────────────────
   For a single large figure (chart, screenshot) with no accompanying
   sidebar content, add class="fig-solo" to the <figure>. The image spans
   the full slide width beneath the title, scaled to fit without cropping
   and without the dark overlay scrim used by fig-full — suited for
   charts/screenshots that carry their own (often white) background.

     # Slide Title

     <figure class="fig-solo">
     <img src="chart.svg" alt="…" />
     </figure>
*/

section:nth-of-type(n+2):has(> figure.fig-solo) {
    display: flex;
    flex-direction: column;
}

section:nth-of-type(n+2):has(> figure.fig-solo) > figure.fig-solo {
    flex: 1 1 auto;
    width: 100%;
    min-height: 0;
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

section:nth-of-type(n+2):has(> figure.fig-solo) > figure.fig-solo img {
    width: 100%;
    height: 100%;
    max-height: 100%;
    object-fit: contain;
    padding: 0;
}

/* ─── Top image band, text below ─────────────────────────────────────────
   For a landscape image (e.g. a UI screenshot) where every part of the
   image matters — so it must never be cropped — and there's too much
   accompanying text to justify a full-bleed fig-full treatment, add
   class="fig-top" to the <figure>. The text below claims exactly the
   height its content needs (normal block flow, not stretched); the image
   band gets whatever vertical space is left over. Every image inside is
   scaled with object-fit: contain, so it's shown complete and unstretched
   regardless of how much or little room ends up available — smaller next
   to a lot of text, larger next to a little. Add more than one <img> to
   show images side-by-side within the same band, each sharing the space
   equally.

     # Slide Title

     <figure class="fig-top">
     <img src="screenshot-a.png" alt="…" />
     <img src="screenshot-b.png" alt="…" />  <!-- optional, shown side-by-side -->
     </figure>

     Any number of content children follow, at full slide width below the figure.
*/

section:nth-of-type(n+2):has(> figure.fig-top) {
    display: flex;
    flex-direction: column;
}

section:nth-of-type(n+2):has(> figure.fig-top) > figure.fig-top {
    flex: 0 1 38vh;   /* natural height; shrinks if text needs more room, never grows past it */
    min-height: 0;
    width: 100%;
    margin: auto 0 1.5vh;   /* auto top + the div's auto bottom below center the group as a whole */
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: stretch;
    gap: 1.5vw;
}

section:nth-of-type(n+2):has(> figure.fig-top) > figure.fig-top img {
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
    object-fit: contain;
}

section:nth-of-type(n+2):has(> figure.fig-top) > :not(figure):not(:first-child):not(footer) {
    flex: 0 0 auto;
    margin-bottom: auto;   /* reuses the same centering trick deck.css uses for non-figure slides */
}

/* .irb-seal: corner-bleed badge (irb-seal.svg, gen-irb-seal.js), opt-in
   via class so no per-slide CSS is needed. No overflow:hidden: article
   already clips the left edge, and the next section's background covers
   the bottom bleed.
   Scoped via :has() to reach (0,0,2,2) — deck.css's
   `section > :not(:first-child)` is (0,0,2,1) and would otherwise win
   the margin-inline fight over a bare .irb-seal (0,0,1,1). */
section:has(img.irb-seal) img.irb-seal {
    position: absolute;
    inset-inline-start: -10.25vh;
    inset-block-end: -12.25vh;
    width: 40vh;
    height: 40vh;
    margin: 0;
    padding: 0;
    max-width: none;
    max-height: none;
    z-index: -1;   /* behind in-flow text/figure content, above section's own background */
    pointer-events: none;
    filter: drop-shadow(0 0.3vh 0.6vh rgba(0, 0, 0, 0.45));
}

/* .centered: shrinks a block to content width then centers it (not
   text-align, which would ragged-center wrapped bullet lines). Works at
   any nesting depth; the second rule re-asserts margin-inline for the
   direct-child case, where it'd otherwise tie deck.css's
   `section > :not(:first-child)` (0,0,2,1). */
.centered {
    width: fit-content;
    max-width: 100%;
    margin-inline: auto;
}

section:nth-of-type(n+2) > .centered {
    margin-inline: auto;
}
