/**
 * gamories.css — shared styles for all Web-Gamories journal pages.
 *
 * Colours, fonts and backgrounds are driven by the --gm-* custom properties
 * below. A journal theme (css/themes/<franchise>/<journal>.css) only needs
 * to override the variables inside its own [data-theme="<journal>"] block
 * to restyle the whole page — including the exportable result.
 *
 * The page IS the result: rows are editable in place, so this file covers
 * both the final look and the editing affordances (drop zones, placeholders,
 * buttons). Everything editor-only is hidden at export via `.gm-exporting`
 * or `[data-export-hide]`.
 *
 * Themes can also restyle the structural classes (.gm-result-card, ...) or add
 * extra decorative rules on top of the shared base.
 *
 * Adding a new game or restyling an existing one? See THEMING.md at the repo
 * root for the checklist and the full --gm-* variable reference.
 */

/* ------------------------------------------------------------------ defaults
 * The :root block doubles as the built-in "default" theme.
 */
:root {
    --gm-font: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    /* Headings inherit the body font unless a theme overrides this. */
    --gm-font-heading: var(--gm-font);

    /* Palette */
    --gm-primary: #667eea;
    --gm-secondary: #764ba2;
    --gm-page-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    --gm-header-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    --gm-header-text: #ffffff;
    --gm-surface: #ffffff;
    --gm-surface-muted: #f8f9fa;
    --gm-text: #333333;
    --gm-text-muted: #666666;
    --gm-border: #dddddd;
    --gm-danger: #ff4757;
    /* Editable-field cue while editing — outline (never a real border) so
       nothing shifts a pixel, plus an optional faint field fill. Both are
       stripped at export by the .gm-exporting rules below. */
    --gm-editable-border: 1px dashed var(--gm-border);
    --gm-editable-bg: transparent;
    /* Page header title & subtitle text — families fall back to the
       heading/body fonts so a theme can override each independently. */
    --gm-title-font: var(--gm-font-heading);
    --gm-title-size: 2.5em;
    --gm-title-weight: 600;
    --gm-title-style: normal;
    --gm-title-spacing: 0.5px;
    --gm-title-color: var(--gm-header-text);
    --gm-subtitle-font: var(--gm-font);
    --gm-subtitle-size: 1.1em;
    --gm-subtitle-weight: 400;
    --gm-subtitle-style: normal;
    --gm-subtitle-spacing: normal;
    --gm-subtitle-color: var(--gm-header-text);
    --gm-subtitle-opacity: 0.9;

    /* Entry caption header & body text. The -colour vars alias the older
       --gm-result-caption-* names so existing theme files keep working. */
    --gm-caption-title-font: var(--gm-font-heading);
    --gm-caption-title-size: 1.3em;
    --gm-caption-title-weight: 700;
    --gm-caption-title-style: normal;
    --gm-caption-title-spacing: normal;
    --gm-caption-title-color: var(--gm-result-caption-title);
    --gm-caption-body-font: var(--gm-font);
    --gm-caption-body-size: 1.1em;
    --gm-caption-body-weight: 400;
    --gm-caption-body-style: italic;
    --gm-caption-body-spacing: normal;
    --gm-caption-body-color: var(--gm-result-caption-text);

    /* Section-header row title (colour defaults to inheriting the
       section band's --gm-header-text). */
    --gm-section-font: var(--gm-font-heading);
    --gm-section-size: 1.5em;
    --gm-section-weight: 700;
    --gm-section-style: normal;
    --gm-section-spacing: normal;
    --gm-section-color: inherit;

    /* Quote row text + attribution line. */
    --gm-quote-font: var(--gm-font);
    --gm-quote-size: 1.4em;
    --gm-quote-weight: 400;
    --gm-quote-style: italic;
    --gm-quote-spacing: normal;
    --gm-quote-color: inherit;
    --gm-quote-attrib-font: var(--gm-font);
    --gm-quote-attrib-size: 1em;
    --gm-quote-attrib-weight: 400;
    --gm-quote-attrib-style: normal;
    --gm-quote-attrib-spacing: normal;
    --gm-quote-attrib-color: var(--gm-text-muted);

    /* Stats row key & value text (the stats title uses the caption-title
       group above). */
    --gm-stat-key-font: var(--gm-font);
    --gm-stat-key-size: 1em;
    --gm-stat-key-weight: 700;
    --gm-stat-key-style: normal;
    --gm-stat-key-spacing: normal;
    --gm-stat-key-color: inherit;
    --gm-stat-value-font: var(--gm-font);
    --gm-stat-value-size: 1em;
    --gm-stat-value-weight: 400;
    --gm-stat-value-style: normal;
    --gm-stat-value-spacing: normal;
    --gm-stat-value-color: inherit;

    /* Page footer text (colour aliases --gm-result-footer-text). */
    --gm-footer-font: var(--gm-font);
    --gm-footer-size: 0.9em;
    --gm-footer-weight: 400;
    --gm-footer-style: normal;
    --gm-footer-spacing: normal;
    --gm-footer-color: var(--gm-result-footer-text);

    /* Ornament divider row (the glyph itself: --gm-ornament below). */
    --gm-ornament-font: var(--gm-font);
    --gm-ornament-size: 1.3em;
    --gm-ornament-weight: 400;
    --gm-ornament-style: normal;
    --gm-ornament-spacing: normal;
    --gm-ornament-color: var(--gm-primary);

    /* Progress bar row — track, fill (gradient allowed) and the fraction
       text inside the bar. */
    --gm-progress-track-bg: var(--gm-surface-muted);
    --gm-progress-fill: var(--gm-primary);
    --gm-progress-height: 30px;
    --gm-progress-font: var(--gm-font);
    --gm-progress-size: 0.95em;
    --gm-progress-weight: 600;
    --gm-progress-style: normal;
    --gm-progress-spacing: normal;
    --gm-progress-text-color: var(--gm-text);

    /* Empty drop-zone icon + hint text. */
    --gm-drop-icon-size: 3em;
    --gm-drop-icon-color: var(--gm-primary);
    --gm-drop-text-size: 0.9em;
    --gm-drop-text-color: var(--gm-text-muted);
    --gm-drop-strong-color: var(--gm-primary);

    /* Edges of the result header — width/style/colour split so themes
       tune each part. */
    --gm-header-border-bottom-width: 3px;
    --gm-header-border-bottom-style: solid;
    --gm-header-border-bottom-color: var(--gm-secondary);
    --gm-header-border-top-width: 0;
    --gm-header-border-top-style: none;
    --gm-header-border-top-color: transparent;

    /* Top/bottom edges of the result page on screen — same split
       convention as the header edges. */
    --gm-page-border-top-width: 0;
    --gm-page-border-top-style: none;
    --gm-page-border-top-color: transparent;
    --gm-page-border-bottom-width: 0;
    --gm-page-border-bottom-style: none;
    --gm-page-border-bottom-color: transparent;

    /* Image frame — the per-row ▣ toggle frames just the picture area.
       A theme opts in by declaring --gm-image-frame-image in ITS OWN
       stylesheet (usually the same square asset as the page frame) —
       or, most robustly, a themed .gm-result-media.gm-image-frame rule
       with a LITERAL url() (urls inside custom properties can resolve
       against the document url on subpath deploys — see the note in
       curseofulatek.css). Width/slice have safe defaults. */
    --gm-image-frame-image: none;
    --gm-image-frame-slice: var(--gm-page-frame-slice, 25%);
    --gm-image-frame-width: 25px;

    /* Border around each entry card (shorthand). */
    --gm-card-border: none;
    /* Background of the round ▦ / ⋮ row-control buttons (the × circles
       use --gm-danger). */
    --gm-row-ctrl-bg: var(--gm-secondary);

    /* Buttons */
    --gm-btn-generate-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    --gm-btn-image-bg: linear-gradient(135deg, #ffc107 0%, #ff8c00 100%);
    /* Text and border ring on all toolbar buttons; "+" insert buttons
       get their own via --gm-insert-btn-color / --gm-insert-btn-border. */
    --gm-btn-text: #ffffff;
    --gm-btn-border: rgba(255, 255, 255, 0.85);
    /* Per-group ring overrides — each falls back to --gm-btn-border so a
       theme only sets the ones it wants to differ. */
    --gm-btn-action-border: var(--gm-btn-border);
    --gm-btn-image-border: var(--gm-btn-border);
    /* "+" insert-point buttons between rows — background falls back to
       the toolbar action colour, glyph to --gm-btn-text, ring to
       --gm-btn-border. */
    --gm-insert-btn-bg: var(--gm-btn-generate-bg);
    --gm-insert-btn-color: var(--gm-btn-text);
    --gm-insert-btn-border: var(--gm-btn-border);

    /* Result page / export */
    --gm-export-bg: #f0f4ff;
    --gm-result-card-bg: #ffffff;
    --gm-result-caption-bg: #f8f9fa;
    --gm-result-caption-title: #333333;  /* caption header text */
    --gm-result-caption-text: #333333;   /* caption body text */
    --gm-result-caption-border: 1px solid var(--gm-border);
    --gm-result-footer-text: #666666;

    /* Shape */
    --gm-radius-lg: 20px;  /* page panel */
    --gm-radius-md: 12px;  /* drop zones */

    /* Ornament divider row glyph (themes override with their own motif) */
    --gm-ornament: '——— ✦ ———';

    /* Journal logo sizing (per-journal via the theme block) */
    --gm-logo-max-height: 140px;
    --gm-logo-max-width: 60%;
}

/* --------------------------------------------------------------------- base */

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: var(--gm-font);
    background: var(--gm-page-bg);
    min-height: 100vh;
}

.gm-navbar {
    background: rgba(0, 0, 0, 0.25);
}

.gm-navbar .navbar-brand,
.gm-navbar .nav-link {
    color: rgba(255, 255, 255, 0.9);
}

/* Editor-only site logo centred above the result page — data-export-hide
   keeps it out of every export (PNG/JPG snapshot). min() caps
   it at 720px on wide screens while keeping it to 80% on small ones so
   it doesn't fill the viewport edge-to-edge on mobile. */
.gm-site-logo {
    display: block;
    margin: 0 auto 35px;
    width: min(720px, 80%);
    height: auto;
}

/* Theme skin over Bootstrap's .container — position/width come from
   Bootstrap, surface/radius/shadow from the game theme. */
.gm-container {
    background: var(--gm-surface);
    border-radius: var(--gm-radius-lg);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
    overflow: hidden;
}

/* The result page's edge accents (top/bottom). */
.gm-result-page {
    border-top: var(--gm-page-border-top-width)
                var(--gm-page-border-top-style)
                var(--gm-page-border-top-color);
    border-bottom: var(--gm-page-border-bottom-width)
                   var(--gm-page-border-bottom-style)
                   var(--gm-page-border-bottom-color);
}

/* -------------------------------------------------------- editable content
 * contenteditable fields render as the final text. Their placeholder, the
 * persistent dotted outline and the dashed focus outline are editor-only —
 * hidden at export. The outline (not a real border) is deliberate:
 * it marks editable fields without shifting a single pixel of layout, so
 * the edit view stays identical to the exported result.
 */
.gm-editable {
    min-height: 1em;
    cursor: text;
    outline: var(--gm-editable-border);
    outline-offset: 2px;
    background: var(--gm-editable-bg);
    /* Small radius keeps single-line fields tidy; the outline follows the
       corners where the browser supports it. */
    border-radius: 6px;
    caret-color: var(--gm-primary);
}

.gm-editable:empty::before {
    content: attr(data-placeholder);
    color: var(--gm-text-muted);
    font-weight: 400;
    font-style: italic;
}

/* Focused fields get a solid primary-colour cue while typing; no hover
 * effects, so nothing shifts under the mouse. */
.gm-editable:focus {
    outline: 1px solid var(--gm-primary);
}

/* ------------------------------------------------------------- drop zone */

.gm-drop-zone {
    position: relative;
    border: 2px dashed var(--gm-border);
    border-radius: var(--gm-radius-md);
    padding: 40px;
    text-align: center;
    cursor: pointer;
    transition: all 0.3s ease;
    min-height: 150px;
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.gm-drop-zone:hover {
    border-color: var(--gm-primary);
}

.gm-drop-icon {
    font-size: var(--gm-drop-icon-size);
    color: var(--gm-drop-icon-color);
    margin-bottom: 10px;
}

.gm-drop-text {
    color: var(--gm-drop-text-color);
    font-size: var(--gm-drop-text-size);
}

.gm-drop-text strong {
    color: var(--gm-drop-strong-color);
}

.gm-file-input,
.gm-bg-input {
    display: none;
}

/* Round × affordances: Bootstrap's btn-close on a themed danger circle.
 * The glyph is an svg held in --bs-btn-close-bg — swapped for a white one
 * so it stays readable on the danger colour (btn-close-white can't be used
 * here: its invert() filter would bleach the circle too). */
.gm-remove-btn,
.gm-row-delete {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 1;
    width: 26px;
    height: 26px;
    padding: 0;
    background-color: var(--gm-danger);
    border-radius: 50%;
    /* Smaller than btn-close's 1em so the × sits inside a field of red. */
    background-size: 10px;
    --bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");
    --bs-btn-close-opacity: 1;
    --bs-btn-close-hover-opacity: 1;
}

.gm-remove-btn {
    display: none;
}

.gm-remove-btn.active {
    display: block;
}

.gm-row-delete {
    top: 8px;
    right: 8px;
}

/* Insert points: a dashed divider line with a "+" dropdown centred on it,
 * rendered before every row and after the last. Negative margins offset
 * the vstack gap-4 so cards keep roughly their original spacing. */
.gm-insert-point {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    margin-block: -0.75rem;
    padding: 4px 0;
}

.gm-insert-point::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    border-top: 1px dashed var(--gm-border);
}

/* Compact "+" trigger — caret hidden, the glyph says it. position:relative
 * lifts it above the dashed line. */
.gm-insert-btn {
    position: relative;
    width: 30px;
    height: 30px;
    padding: 0;
    font-size: 1.1rem;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* The .gm-btn-action rule (below, higher in source order) sets
       --bs-btn-bg/--bs-btn-color from --gm-btn-generate-bg/--gm-btn-text —
       re-pointing those variables on this element is all it takes; no
       specificity fight needed. */
    --gm-btn-generate-bg: var(--gm-insert-btn-bg);
    --gm-btn-text: var(--gm-insert-btn-color);
    --gm-btn-border: var(--gm-insert-btn-border);
}

.gm-insert-btn::after {
    display: none;
}

/* In-place row controls: themed circles in the caption corner, ordered
 * left to right — ▣ image frame (media rows only), ↑ move up, ↓ move
 * down, ⧉ duplicate, ▦ type switcher, 🖼 row background, × delete. The
 * dropdown wrappers hold their positions so the menus anchor correctly. */
.gm-row-up,
.gm-row-down,
.gm-row-dup,
.gm-row-frame {
    position: absolute;
    top: 8px;
    z-index: 1;
}

/* The ▣ frame button sits leftmost — on rows without media it's removed
 * and the empty slot just stays invisible at the cluster's far end. */
.gm-row-frame { right: 200px; }
.gm-row-up { right: 168px; }
.gm-row-down { right: 136px; }
.gm-row-dup { right: 104px; }

.gm-row-type {
    position: absolute;
    top: 8px;
    right: 72px;
    z-index: 1;
}

.gm-row-bg {
    position: absolute;
    top: 8px;
    right: 40px;
    z-index: 1;
}

/* ↑ ↓ ⧉ ▦ 🖼 ▣ are text glyphs (font characters), so they scale with the
 * button and need no svg handling. */
.gm-type-btn,
.gm-bg-btn,
.gm-ctrl-btn {
    width: 26px;
    height: 26px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: var(--gm-row-ctrl-bg);
    color: #ffffff;
    font-size: 13px;
    line-height: 26px;
    text-align: center;
    cursor: pointer;
}

/* The 🖼 button tints when its row carries a background, ▣ when the
   image frame is on. */
.gm-bg-btn.active,
.gm-row-frame.active {
    background: var(--gm-primary);
}

/* ----------------------------------------------------------------- buttons
 * Themed Bootstrap `btn` components: each gm-btn-* class maps the game's
 * --gm-btn-* colour onto Bootstrap's --bs-btn-* API (hover/active keep the
 * same colour — no motion effects anywhere on this page).
 */
.gm-btn-action,
.gm-btn-image {
    --bs-btn-color: var(--gm-btn-text);
    --bs-btn-hover-color: var(--gm-btn-text);
    --bs-btn-active-color: var(--gm-btn-text);
    /* Light outline keeps the themed gradients readable as pressable
       buttons against any page surface. */
    --bs-btn-border-width: 2px;
    --bs-btn-border-color: var(--gm-btn-border);
    --bs-btn-hover-border-color: var(--gm-btn-border);
    --bs-btn-active-border-color: var(--gm-btn-border);
    --bs-btn-font-weight: 600;
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.35);
}

.gm-btn-action {
    --bs-btn-bg: var(--gm-btn-generate-bg);
    --bs-btn-hover-bg: var(--gm-btn-generate-bg);
    --bs-btn-active-bg: var(--gm-btn-generate-bg);
    --gm-btn-border: var(--gm-btn-action-border);
}

.gm-btn-image {
    --bs-btn-bg: var(--gm-btn-image-bg);
    --bs-btn-hover-bg: var(--gm-btn-image-bg);
    --bs-btn-active-bg: var(--gm-btn-image-bg);
    --gm-btn-border: var(--gm-btn-image-border);
}

/* ------------------------------------------------------------ result page */

.gm-result-header {
    background: var(--gm-header-bg);
    color: var(--gm-header-text);
    padding: 40px 20px;
    text-align: center;
    border-bottom: var(--gm-header-border-bottom-width)
                   var(--gm-header-border-bottom-style)
                   var(--gm-header-border-bottom-color);
    border-top: var(--gm-header-border-top-width)
                var(--gm-header-border-top-style)
                var(--gm-header-border-top-color);
}

/* Journal logo (config.logo) at the top of the header. Sizing comes from
   --gm-logo-* vars so each theme adjusts it; deeper changes (shadows,
   frames) go through .gm-journal-logo in the theme file. */
.gm-journal-logo {
    display: block;
    margin: 0 auto 15px;
    max-width: var(--gm-logo-max-width);
    max-height: var(--gm-logo-max-height);
}

/* Page title + subtitle: every aspect is a --gm-title-* or
   --gm-subtitle-* variable so themes tune without touching selectors. */
.gm-result-title {
    font-family: var(--gm-title-font);
    font-size: var(--gm-title-size);
    font-weight: var(--gm-title-weight);
    font-style: var(--gm-title-style);
    letter-spacing: var(--gm-title-spacing);
    color: var(--gm-title-color);
    margin-bottom: 10px;
}

.gm-result-header p {
    font-family: var(--gm-subtitle-font);
    font-size: var(--gm-subtitle-size);
    font-weight: var(--gm-subtitle-weight);
    font-style: var(--gm-subtitle-style);
    letter-spacing: var(--gm-subtitle-spacing);
    color: var(--gm-subtitle-color);
    opacity: var(--gm-subtitle-opacity);
}

/* One row per entry. Each card holds a Bootstrap row split into
   col-md-8 (picture, 2/3) + col-md-4 (caption pane, 1/3). */
.gm-result-card {
    background: var(--gm-result-card-bg);
    border: var(--gm-card-border);
    border-radius: 15px;
    overflow: hidden;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}

/* Optional row background image (set per row via the 🖼 control). The url,
 * size and repeat arrive as inline custom properties — using properties
 * rather than background: shorthand keeps the card's theme colour as the
 * under-layer beneath the image. */
.gm-row-has-bg {
    background-image: var(--gm-row-bg);
    background-size: var(--gm-row-bg-size);
    background-repeat: var(--gm-row-bg-repeat);
    background-position: center;
}

/* Caption panes and quotes go transparent so the texture spans the whole
   row — readability is on the chosen image, same as the page background. */
.gm-row-has-bg .gm-result-caption,
.gm-row-has-bg .gm-quote {
    background: transparent;
}

/* Orientation: rows carrying .gm-row-flipped put the picture on the right
   at the md breakpoint and up. Below md the Bootstrap columns stack
   full-width in DOM order (image first) automatically. The orientation is
   a per-row class, so empty hidden rows can't disturb the layout. */
@media (min-width: 768px) {
    .gm-result-card.gm-row-flipped .gm-result-media {
        order: 2;
    }
}

/* The 2/3 picture area: a drop zone until filled, then the image itself at
 * natural aspect ratio, capped at 80vh with contain (taller images
 * letterbox inside the area instead of cropping). */
.gm-result-media {
    position: relative;
    display: flex;
}

/* Drag-over highlight — on the area so it also covers filled rows. */
.gm-result-media.active {
    outline: 3px dashed var(--gm-primary);
    outline-offset: -3px;
}

/* Filled/unfilled is tracked per media zone (.gm-media-filled), not per
 * row — gallery rows mix filled and empty slots side by side. */
.gm-media-filled .gm-drop-zone {
    display: none;
}

/* Empty picture areas assume the common 16:9 screenshot ratio so the
 * editor previews the final proportions. Filled slots keep the image's
 * natural aspect ratio — the ratio only shapes the placeholder. */
.gm-result-media:not(.gm-media-filled) .gm-drop-zone {
    aspect-ratio: 16 / 9;
}

.gm-result-image {
    display: none;
    width: 100%;
    height: auto;
    max-height: 80vh;
    object-fit: contain;
}

.gm-media-filled .gm-result-image {
    display: block;
}

.gm-result-caption {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 10px;
    padding: 30px 20px;
    text-align: center;
    color: var(--gm-caption-body-color);
    background: var(--gm-result-caption-bg);
    border-inline-start: var(--gm-result-caption-border);
}

/* On flipped rows the caption sits left, so the divider moves to its
   right edge. */
.gm-result-card.gm-row-flipped .gm-result-caption {
    border-inline-start: none;
    border-inline-end: var(--gm-result-caption-border);
}

/* ------------------------------------------------------- row type variants
 * Additional templates from ROW_TYPES. Modifier classes sit on the card. */

/* Photo card: image full-width on top, caption below — the divider moves
   to the caption's top edge. */
.gm-card-photo .gm-result-caption {
    border-inline-start: none;
    border-top: var(--gm-result-caption-border);
}

/* Full-width image: media fills the card; the row controls move to the
   media's top-left so they don't fight the image remove × at top-right. */
.gm-card-full .gm-result-media {
    width: 100%;
}

.gm-card-full .gm-row-up {
    right: auto;
    left: 8px;
}

.gm-card-full .gm-row-down {
    right: auto;
    left: 40px;
}

.gm-card-full .gm-row-dup {
    right: auto;
    left: 72px;
}

.gm-card-full .gm-row-type {
    right: auto;
    left: 104px;
}

.gm-card-full .gm-row-bg {
    right: auto;
    left: 136px;
}

.gm-card-full .gm-row-delete {
    right: auto;
    left: 168px;
}

.gm-card-full .gm-row-frame {
    right: auto;
    left: 200px;
}

/* Text note: the caption pane is the whole card, no divider needed. */
.gm-card-text .gm-result-caption {
    border: none;
}

/* Gallery rows (2/3-photo): equal-width slots, each a photo over its own
 * caption. Images keep natural aspect — slot heights may differ, and each
 * caption stretches to match its tallest sibling. */
.gm-gallery {
    display: flex;
    gap: 10px;
}

.gm-gallery-slot {
    flex: 1 1 0;
    min-width: 0; /* lets slots shrink below their image's intrinsic width */
    display: flex;
    flex-direction: column;
}

/* Each slot's caption sits under its image, so the divider moves to the
   caption's top edge (same variable as the side dividers elsewhere). */
.gm-gallery-slot .gm-result-caption {
    flex: 1;
    justify-content: flex-start;
    padding: 15px 10px;
    border-inline-start: none;
    border-top: var(--gm-result-caption-border);
}

/* Section header: a centred title band reusing the header palette to read
   as a chapter divider. Themes can restyle it like any other class. */
.gm-section-header {
    position: relative;
    padding: 25px 60px; /* side padding leaves room for the corner controls */
    text-align: center;
    background: var(--gm-header-bg);
    color: var(--gm-header-text);
}

.gm-section-title {
    font-family: var(--gm-section-font);
    font-size: var(--gm-section-size);
    font-weight: var(--gm-section-weight);
    font-style: var(--gm-section-style);
    letter-spacing: var(--gm-section-spacing);
    color: var(--gm-section-color);
}

/* Quote: oversized italic text with an attribution line, on the caption
   surface so it reads like the other text cards. */
.gm-quote {
    position: relative;
    padding: 35px 50px;
    text-align: center;
    background: var(--gm-result-caption-bg);
    color: var(--gm-caption-body-color);
}

.gm-quote-text {
    font-family: var(--gm-quote-font);
    font-size: var(--gm-quote-size);
    font-weight: var(--gm-quote-weight);
    font-style: var(--gm-quote-style);
    letter-spacing: var(--gm-quote-spacing);
    color: var(--gm-quote-color);
}

.gm-quote-attrib {
    margin-top: 12px;
    font-family: var(--gm-quote-attrib-font);
    font-size: var(--gm-quote-attrib-size);
    font-weight: var(--gm-quote-attrib-weight);
    font-style: var(--gm-quote-attrib-style);
    letter-spacing: var(--gm-quote-attrib-spacing);
    color: var(--gm-quote-attrib-color);
}

/* Stats: a titled list of editable key: value pairs. */
.gm-stats {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 8px;
}

.gm-stat {
    display: flex;
    gap: 6px;
    justify-content: center;
    align-items: baseline;
}

.gm-stat-key {
    font-family: var(--gm-stat-key-font);
    font-size: var(--gm-stat-key-size);
    font-weight: var(--gm-stat-key-weight);
    font-style: var(--gm-stat-key-style);
    letter-spacing: var(--gm-stat-key-spacing);
    color: var(--gm-stat-key-color);
}

.gm-stat-value {
    font-family: var(--gm-stat-value-font);
    font-size: var(--gm-stat-value-size);
    font-weight: var(--gm-stat-value-weight);
    font-style: var(--gm-stat-value-style);
    letter-spacing: var(--gm-stat-value-spacing);
    color: var(--gm-stat-value-color);
}

/* Small red × per stat line — same circle as the row controls. */
.gm-stat-remove {
    width: 16px;
    height: 16px;
    padding: 0;
    background-color: var(--gm-danger);
    border-radius: 50%;
    background-size: 7px;
    align-self: center;
    --bs-btn-close-opacity: 1;
    --bs-btn-close-hover-opacity: 1;
}

/* Editor-only mini-button inside the stats row. */
.gm-stat-add {
    margin-top: 10px;
    padding: 0;
    border: none;
    background: none;
    color: var(--gm-primary);
    font-size: 0.85em;
    cursor: pointer;
}

/* Progress bar row: a themed track with a width-driven fill; the
   "7 / 10" fraction is two editable fields centred over the bar. */
.gm-progress {
    position: relative;
    height: var(--gm-progress-height);
    margin-top: 10px;
    border-radius: var(--gm-radius-md);
    background: var(--gm-progress-track-bg);
    overflow: hidden;
}

.gm-progress-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 0;
    background: var(--gm-progress-fill);
    transition: width 0.3s ease;
}

.gm-progress-label {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.15em;
    font-family: var(--gm-progress-font);
    font-size: var(--gm-progress-size);
    font-weight: var(--gm-progress-weight);
    font-style: var(--gm-progress-style);
    letter-spacing: var(--gm-progress-spacing);
    color: var(--gm-progress-text-color);
}

/* Ornament divider: the glyph comes from the theme's --gm-ornament var;
   the card is the positioning context for the row controls. */
.gm-card-ornament {
    position: relative;
}

.gm-ornament {
    padding: 18px;
    text-align: center;
    font-family: var(--gm-ornament-font);
    font-size: var(--gm-ornament-size);
    font-weight: var(--gm-ornament-weight);
    font-style: var(--gm-ornament-style);
    letter-spacing: var(--gm-ornament-spacing);
    color: var(--gm-ornament-color);
}

.gm-ornament::before {
    content: var(--gm-ornament);
}

.gm-result-caption-title {
    font-family: var(--gm-caption-title-font);
    font-size: var(--gm-caption-title-size);
    font-weight: var(--gm-caption-title-weight);
    font-style: var(--gm-caption-title-style);
    letter-spacing: var(--gm-caption-title-spacing);
    color: var(--gm-caption-title-color);
}

.gm-result-caption-body {
    font-family: var(--gm-caption-body-font);
    font-size: var(--gm-caption-body-size);
    font-weight: var(--gm-caption-body-weight);
    font-style: var(--gm-caption-body-style);
    letter-spacing: var(--gm-caption-body-spacing);
    color: var(--gm-caption-body-color);
}

.gm-result-footer {
    text-align: center;
    padding: 20px;
    font-family: var(--gm-footer-font);
    font-size: var(--gm-footer-size);
    font-weight: var(--gm-footer-weight);
    font-style: var(--gm-footer-style);
    letter-spacing: var(--gm-footer-spacing);
    color: var(--gm-footer-color);
}

/* ----------------------------------------------------------- export state
 * Toggled on the result page while html2canvas runs: strips every editing
 * affordance plus unfinished rows from the snapshot.
 */
.gm-exporting [data-export-hide],
.gm-exporting .gm-row-empty {
    display: none !important;
}

/* Empty gallery slots collapse at export so filled photos take the full
 * width; a slot with a caption but no image keeps its text only. */
.gm-exporting .gm-gallery-slot.gm-slot-empty,
.gm-exporting .gm-result-media:not(.gm-media-filled) {
    display: none !important;
}

.gm-exporting .gm-editable:empty::before {
    display: none !important;
}

.gm-exporting .gm-editable {
    outline: none !important;
    background: none !important;
}

/* Export frame pieces (.gm-frame-piece) are divs gamories.js creates,
   positions and fills inside a border-image element at export time —
   html2canvas can't render border-image. Fully inline-styled by the
   engine, removed after the snapshot; no css needed. */

/* Image frame — the row's ▣ toggle puts .gm-image-frame on each media
   zone, wrapping just the picture area in the same square asset as the
   page frame, thinner (--gm-image-frame-*). */
.gm-result-media.gm-image-frame {
    border: var(--gm-image-frame-width) solid transparent;
    border-image: var(--gm-image-frame-image) var(--gm-image-frame-slice) /
                  var(--gm-image-frame-width) repeat;
}

/* ----------------------------------------------------------------- loading */

.gm-loading {
    display: none;
    text-align: center;
    padding: 40px;
}

.gm-loading.active {
    display: block;
}

/* Bootstrap spinner-border inherits this theme colour. */
.gm-spinner {
    color: var(--gm-primary);
    margin-bottom: 20px;
}

/* -------------------------------------------------------------- responsive */

/* Below Bootstrap's md breakpoint the columns stack full-width (image on
   top); only the divider needs to move to the caption's top edge. */
@media (max-width: 767.98px) {
    .gm-result-caption,
    .gm-result-card.gm-row-flipped .gm-result-caption {
        border-inline-start: none;
        border-inline-end: none;
        border-top: var(--gm-result-caption-border);
    }

    /* Gallery slots stack vertically — each photo keeps its own caption. */
    .gm-gallery {
        flex-direction: column;
    }
}
