/*
 * Article body media — shared by resources/article_detail.html and
 * resources/blog_detail.html. Markup comes from the `article_media`
 * template filter (apps/resources/templatetags/markdown_extras.py).
 *
 * Flat only: the table edge indicator is two solid stepped bands, never a
 * gradient.
 */

/* Markdown body images: cap tall (portrait) frames to the viewport and
   centre them instead of letting them run several screens tall. Scoped to
   images directly in a paragraph (optionally inside a link) so figures,
   image rows and gated maps keep their own sizing. Images that carry an
   author-set width/height are left at that size; dimensions the filter read
   from the file are marked data-media-size. :where() keeps the specificity
   of the plain `p > img` selector so the SVG `width: 100%` rule still wins. */
.article-content p > img:where(:not([width], [height])),
.article-content p > a > img:where(:not([width], [height])),
.article-content p > img[data-media-size],
.article-content p > a > img[data-media-size] {
    max-height: min(85vh, 900px);
    width: auto;
    margin-inline: auto;
    display: block;
}

/* Measured raster images (the filter sets data-media-size plus --media-w /
   --media-ratio): the same width `auto` resolves to after load — natural
   width, column width or the height cap, whichever is smallest — but known
   before the file arrives, so the width/height attributes reserve the
   space. */
.article-content p > img[data-media-size],
.article-content p > a > img[data-media-size] {
    width: min(100%, var(--media-w), calc(min(85vh, 900px) * var(--media-ratio)));
}

/* SVG charts link to the full-size file so phones can open and zoom them. */
.article-content .article-media-zoom {
    display: block;
    cursor: zoom-in;
}

/* Tables scroll horizontally inside a frame; the frame shows a flat edge
   band on whichever side still has hidden columns (state set by
   static/js/article-media.js). */
.article-content .table-scroll-frame {
    position: relative;
    margin: 2rem 0;
}

.article-content .table-scroll-frame > .table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin: 0;
}

/* The wrapper is the only scroller. The blog page's legacy table rule
   (display: block; overflow-x: auto) would otherwise make the table scroll
   itself, so the wrapper never overflows and no edge band ever shows. */
.article-content .table-scroll > table {
    display: table;
    overflow: visible;
    max-width: none;
    margin: 0;
}

.article-content .table-scroll-frame::before,
.article-content .table-scroll-frame::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2rem;
    box-sizing: border-box;
    background-color: rgba(255, 255, 255, 0.85);
    background-clip: padding-box;
    pointer-events: none;
    opacity: 0;
    transition: opacity 160ms ease-out;
}

.article-content .table-scroll-frame::before {
    left: 0;
    border-right: 0.75rem solid rgba(255, 255, 255, 0.45);
}

.article-content .table-scroll-frame::after {
    right: 0;
    border-left: 0.75rem solid rgba(255, 255, 255, 0.45);
}

.article-content .table-scroll-frame.has-more-start::before,
.article-content .table-scroll-frame.has-more-end::after {
    opacity: 1;
}

@media (max-width: 640px) {
    .article-content .table-scroll-frame {
        margin: 1.5rem 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .article-content .table-scroll-frame::before,
    .article-content .table-scroll-frame::after {
        transition: none;
    }
}
