/* css/marketplace.css
 *
 * The Marketplace page: the filter panel down the left, the wall of listings
 * on the right, and one listing on its own.
 *
 * WHY THIS IS NOT css/blog.css WITH A FIND AND REPLACE
 *
 * It very nearly is, and that was considered. The two pages solve the same
 * layout problem and the panel's internals here are deliberately the blog's,
 * measurement for measurement, so the site has one idea of what a filter panel
 * looks like rather than two.
 *
 * They are separate files because the two pages diverge where it matters. The
 * blog's results are its own markup; the Marketplace's are the dashboard's
 * script cards, which bring their own grid, their own hover and their own
 * breakpoints. Sharing a stylesheet would mean .blog-list rules that must never
 * touch a .dash-card and .dash-card rules that must never touch a blog post,
 * all in one file, distinguished by nothing but the author's memory.
 *
 * The panel is a sticky <aside> in the content flow, NOT a second fixed
 * sidebar. .sidebar is position:fixed and .main-wrap is offset by its width; a
 * second one of those would have to be fought at every breakpoint. In the flow
 * it stacks above the results when the window narrows, which is what a filter
 * panel should do.
 *
 * The card classes themselves -- .dash-card-author and the avatar in it -- are
 * NOT here. They belong to the card system and live with the rest of it in
 * css/dashboard.css.
 */

.mk-wrap {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}

/* ---- filter panel ------------------------------------------------------- */
.mk-filters {
    position: sticky;
    top: calc(var(--header-height, 60px) + 16px);
    max-height: calc(100vh - var(--header-height, 60px) - 32px);
    overflow-y: auto;
    background: var(--card-bg, #fff);
    border: 1px solid var(--border-color, #e5e7eb);
    border-radius: 8px;
    padding: 16px;
}

.mk-filter-toggle {
    display: none;
}

.mk-filter-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 14px;
}

.mk-filter-head h4 {
    margin: 0;
    font-size: .95rem;
}

.mk-clear {
    font-size: .78rem;
    color: var(--text-muted, #6b7280);
}

.mk-filter-group {
    margin-bottom: 18px;
}

.mk-filter-label {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-muted, #6b7280);
    margin-bottom: 7px;
}

/* "(all selected)" beside the Genre heading. Not uppercased with the heading
   it sits in: it is a sentence about how the boxes below behave, not a label,
   and small caps make a phrase like that harder to read rather than easier. */
.mk-filter-hint {
    text-transform: none;
    letter-spacing: 0;
    font-style: italic;
    opacity: .8;
}

.mk-search,
.mk-select {
    width: 100%;
    padding: 7px 10px;
    border: 1px solid var(--border-color, #ccd2dc);
    border-radius: 5px;
    font: inherit;
    font-size: .88rem;
    box-sizing: border-box;
    background: #fff;
}

.mk-facet {
    list-style: none;
    margin: 0;
    padding: 0;
}

.mk-facet li {
    margin-bottom: 3px;
}

.mk-facet label {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px;
    border-radius: 4px;
    cursor: pointer;
    font-size: .87rem;
}

.mk-facet label:hover {
    background: var(--hover-bg, #f4f6f9);
}

.mk-facet input {
    margin: 0;
    flex: none;
}

.mk-facet-name {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The hand that marks a request on the cards, in front of the filter that
   finds them, so the control and its results are recognisably the same
   subject. Muted: it is a label's ornament, not one of the coloured state
   marks -- see .mk-req-mark. */
.mk-facet-icon {
    margin-right: 5px;
    color: var(--text-muted);
}

.mk-facet-count {
    flex: none;
    font-size: .75rem;
    color: var(--text-muted, #6b7280);
    background: var(--hover-bg, #eef1f5);
    border-radius: 10px;
    padding: 1px 7px;
}

.mk-facet-any {
    font-style: italic;
    color: var(--text-muted, #6b7280);
}

/* The genre list grows as the site does, so cap it rather than pushing the
   length bands off the bottom of the panel. */
.mk-facet-scroll {
    max-height: 260px;
    overflow-y: auto;
}

/* ---- the change-confirmed toast ----------------------------------------- */

/* Across the top of the screen for a second when a screenplay goes into or
   comes out of the Marketplace -- see mkToast() in js/marketplace.js, which
   carries the padding and the timing. What is here is only the type, which the
   Swal options cannot set.

   Bigger than the site's other toast, on purpose: that one is a background
   notification and this is the whole of the answer to a click that was just
   made, so it is meant to be caught out of the corner of the eye rather than
   read carefully. */
.mkToastPopup .swal2-title {
    font-size: 19px;
    line-height: 1.2;
    padding: 0;
    margin: 0;
    color: var(--text-dark);
}

.mkToastPopup .swal2-icon {
    font-size: 22px;
}

/* ---- the Staff view ----------------------------------------------------- */

/* Dashed rather than solid, matching .blog-staff-only: the site has one way of
   saying "this box is not what everybody sees", and two would be one too many. */
.mk-staff-only {
    border: 1px dashed var(--border-color, #d6d0bf);
    border-radius: 6px;
    padding: 10px 12px;
    background: rgba(0, 0, 0, .015);
}

.mk-staff-only .mk-filter-label {
    margin-bottom: 5px;
}

/* Said again beside the result count, because the number means something
   different with the box ticked and the panel may be scrolled away. */
.mk-scope-note {
    font-size: .8rem;
    font-style: italic;
    color: var(--text-muted, #8094ae);
}

/* Which of these the author actually offered. Only ever drawn in the Staff
   view -- on the ordinary wall every card is listed and a badge on all of them
   would say nothing. */
.mk-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 9px;
    border-radius: 11px;
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    white-space: nowrap;
    border: 1px solid transparent;
}

.mk-badge-on {
    background: #dff5ea;
    border-color: #9fd9bd;
    color: #17694a;
}

/* Muted, not alarming. An unlisted screenplay is the ordinary state of a
   script and not a fault -- most of them will never be offered, and a red
   badge down a wall of ninety-seven would read as ninety-seven problems. */
.mk-badge-off {
    background: var(--hover-bg, #eef1f5);
    border-color: var(--border-color, #d8dde5);
    color: var(--text-muted, #8094ae);
}

/* Switched on by its author, but their membership no longer covers the
   Marketplace, so no member can see it. Amber rather than green or grey: it is
   neither of the ordinary states, and it is the one worth a second look --
   somebody who meant to be selling here and does not know they are not.
   Wider than the other two, so a badged card reserves room for this one. */
.mk-badge-lapsed {
    background: #fdf3d8;
    border-color: #edd08a;
    color: #8a6416;
}

/* ---- the wall ----------------------------------------------------------- */
.mk-list-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px 20px;
    /* The pager up here can be eleven buttons wide, so the row has to be
       allowed to break rather than squeeze the count into two words a line. */
    flex-wrap: wrap;
    /* Indented to the cards below it.
     *
     * The wall of cards is .dash-grid or .dash-rows, and both carry padding:10px
     * -- so the first card starts 10px in from the panel's edge and the last one
     * ends 10px short of it. This row is a sibling of that wall with no padding
     * of its own, so without this the count hangs off the left of the cards and
     * the pager and shape switch hang off their right.
     *
     * Both ends, not just the left: the overhang was symmetrical and so is the
     * fix. Hardcoded rather than read from a variable because the 10px belongs
     * to those two dashboard classes and there is no token for it -- if that
     * padding ever changes, this is the line that has to change with it. */
    padding: 0 10px;
    margin-bottom: 6px;
}

.mk-result-count {
    font-size: 18px;
    color: var(--text-muted, #6b7280);
}

/* The pager and the shape switch as one block on the right, so the pager sits
   against the buttons instead of drifting into the middle of the row. */
.mk-list-tools {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-left: auto;
}

/* The foot's pager stands off the last row of cards; this one is already inside
   a row that has its own spacing, and the 22px would push the switch beside it
   out of line with the count. */
.mk-list-tools .mk-pager {
    margin-top: 0;
    /* Not centred like the one at the foot: this pager is the right-hand end of
       a row, and centring it would leave a gap between it and the switch that
       grows and shrinks with the number of pages. */
    justify-content: flex-end;
}

/* Dimmed rather than emptied while a new page is fetched.
   Blanking the panel makes every filter click three events to watch -- results
   go, pause, results come back -- and the blank is the worst of the three,
   because the page collapses and then jumps as it refills. See listBusy() in
   js/dashboard.js, which makes the same argument at length about the lists it
   owns. Pointer events go with the dimming, so a card cannot be clicked in the
   moment before it is replaced by a different one. */
.mk-list.is-loading {
    opacity: .45;
    pointer-events: none;
    transition: opacity .12s;
}

.mk-empty {
    text-align: center;
    padding: 50px 20px;
    color: var(--text-muted, #6b7280);
}

.mk-empty i {
    font-size: 2rem;
    opacity: .35;
}

.mk-empty p {
    margin: 0;
}

/* Windowed -- at most eleven controls whatever the page count. See
   listPagerBlock() in includes/listlayout.php, which decides which numbers
   these are; what is here is only how they look. flex-wrap survives from the
   old unbounded pager and is kept as a floor rather than a plan: eleven small
   buttons still need somewhere to go on a narrow phone. */
.mk-pager {
    display: flex;
    gap: 6px;
    justify-content: center;
    align-items: center;
    margin-top: 22px;
    flex-wrap: wrap;
}

.mk-page {
    min-width: 34px;
    padding: 6px 10px;
    text-align: center;
    border: 1px solid var(--border-color, #e5e7eb);
    border-radius: 5px;
    text-decoration: none;
    color: inherit;
    font-size: .85rem;
}

.mk-page:hover {
    background: var(--hover-bg, #f4f6f9);
    cursor: pointer;
}

.mk-page.current {
    background: var(--primary, #e85347);
    border-color: var(--primary, #e85347);
    color: #fff;
}

/* Prev and Next. Wider than a number because they carry a word beside the
   chevron, and they keep their place at both ends of the row on every page --
   greyed where there is nowhere to go, rather than removed, so the numbers
   between them do not shift sideways on the first and last page. */
.mk-page-nav {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.mk-page-nav.is-disabled {
    opacity: .4;
    cursor: default;
    pointer-events: none;
}

/* The word goes at the narrowest widths and the chevron stands alone. Both
   arrows keep an accessible name either way -- see the aria-labels in
   listPagerBlock() -- so nothing is lost by hiding the text. */
@media (max-width: 480px) {
    .mk-page-nav span {
        display: none;
    }
}

/* Not a button: nothing to click, nowhere to go. Sized to a number so the row
   does not visibly tighten where a run has been left out. */
.mk-gap {
    min-width: 20px;
    text-align: center;
    color: var(--text-muted, #8094ae);
    font-size: .85rem;
    user-select: none;
}

/* ---- one listing -------------------------------------------------------- */

/* NO WIDTH CAP.
 *
 * This was 1000px, which on a wide window left the listing sitting in the
 * left two thirds of the page with a band of empty grey beside it -- and
 * beside it only, because the blocks under the card were capped to the same
 * 1000 and the page they sit on is not. It read as a layout that had failed
 * to fill rather than as a column somebody had chosen.
 *
 * The author own summary page has never had one, and this is the same
 * screenplay seen by somebody else: the two now measure the same.
 *
 * The cost is honest and worth stating -- a logline and a synopsis set the
 * full width of a large monitor are a long line to read. Nothing else on the
 * page suffers: the poster is a fixed column, the cast and the images are
 * grids that simply fit more across, and a coverage report is already broken
 * into its own panels. */
.mk-listing {
    width: 100%;
}

.mk-listing .back-btn {
    margin-bottom: 10px;
}

.mk-listing-grid {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 24px;
    align-items: start;
    padding: 20px;
}

.mk-listing-poster img {
    width: 100%;
    border-radius: 8px;
    display: block;
}

/* Stretched to the row, not just to its own contents.
 *
 * The grid is align-items:start, so each column stands only as tall as what is
 * in it -- which is right for the poster and wrong for this. A listing with a
 * short logline and no genres left the action buttons floating well above the
 * bottom of the poster beside them, so where they landed depended on how much
 * the writer had filled in.
 *
 * align-self overrides that for this column alone: the poster keeps its natural
 * height, the body matches whichever of the two is taller, and the auto margin
 * on the actions below has somewhere to push into. When the body is the taller
 * of the two this does nothing at all, which is the case it must not disturb. */
.mk-listing-body {
    display: flex;
    flex-direction: column;
    gap: 14px;
    align-self: stretch;
}

.mk-listing-title {
    margin: 0;
    font-size: 26px;
    font-weight: 700;
    color: var(--text-dark);
    line-height: 1.15;
}

/* Directly under the title and lighter, as it is on a card: an episode name is
   read as the second half of the title, not as another fact about the script.
   Its own margin rather than the body's gap, which would separate the two. */
.mk-listing-episode {
    margin: -10px 0 0;
    font-size: 17px;
    color: var(--text-soft);
}

.mk-listing-logline {
    margin: 0;
    font-size: 20px;
    line-height: 1.3;
    color: var(--color-blue);
}

.mk-listing-section p {
    margin: 4px 0 0;
    color: var(--text-soft);
    line-height: 1.35;
}

.mk-listing-genres {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
}

/* Pinned to the bottom right of the card, wherever the text above it ends.
 *
 * margin-top:auto rather than position:absolute. It puts the buttons in the
 * same place -- the foot of the tallest column, inside the card's padding --
 * without taking them out of the flow, which matters for the two cases absolute
 * positioning gets wrong: a long synopsis would run underneath a pinned button
 * unless the card reserved a strip for it, and at the narrow breakpoint the
 * grid collapses to one column and "the bottom of the card" stops being where
 * this belongs. In the flow it simply follows the content there.
 *
 * flex-end because the pair reads as a card footer: the two buttons stay
 * together and sit against the right edge rather than trailing off the left. */
.mk-listing-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 10px;
    margin-top: auto;
    padding-top: 6px;
}

.mk-author {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 6px;
    width: fit-content;
}

.mk-author-avatar {
    width: 34px;
    height: 34px;
    flex: none;
    border-radius: 50%;
    overflow: hidden;
    background: var(--primary-dim);
    color: var(--primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 700;
}

.mk-author-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ---- what the AI made of it, under the listing card --------------------- */

/* A block of its own below the card, not inside it -- see renderMarketplaceAi().
   The report markup itself is the summary page's, and its stylesheet is already
   loaded here (both pages are the dashboard), so what is needed is only the
   frame around it. */
.mk-listing-ai {
    margin-top: 14px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.mk-ai-block {
    background: var(--card-bg, #fff);
    border: 1px solid var(--border-color, #e5e7eb);
    border-radius: 8px;
    padding: 16px 20px;
}

/* The label sits above its report rather than inline with it, as the section
   labels inside the card do. */
.mk-ai-block .script-section-label {
    display: block;
    margin-bottom: 10px;
}

/* The images grid is the Attachments widget's own markup -- .media-image-grid
   and .media-image-item, both already styled in css/dashboard.css -- so it needs
   nothing here beyond room to breathe under the label above it. */
.mk-ai-block .media-image-grid {
    margin-top: 6px;
}

/* ---- Coverage, Story Breakdown and Scene Board, as tabs ------------------

   Built by renderMarketplaceAi(). Radios and labels, switched here with no
   script: the radios come first in the markup, so each can reach its label
   and its pane with ~. The radios are hidden from sight but not from the
   keyboard -- Tab reaches the group and the arrow keys change tab. */
.mk-tabs {
    padding-top: 6px;
}

.mk-tab-input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    pointer-events: none;
}

.mk-tab-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 0 0 14px;
    border-bottom: 1px solid var(--border);
}

/* The site's tab look -- .nav-tabs .nav-link in css/dashboard.css. */
/* Set like .nav-tabs .nav-link, because it is the same thing.
 *
 * This is a different class only because it is a CSS-only tab strip -- radios
 * and labels, no JavaScript -- built for a page that may be read by somebody
 * who is not signed in. A reader does not know that. They see the tab row on a
 * Library listing and the tab row on the script summary card, and those two
 * were 17px sentence case and 16px uppercase.
 *
 * So: 16px, uppercase, .04em, the same as every other tab row on the site. The
 * padding stays its own -- this strip sits under a listing rather than inside
 * a card column and has never been short of width. */
.mk-tab {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    /* 6px under against 10 over -- the same uneven padding every other tab
       strip carries, and for the same reason: uppercase has no descenders. */
    padding: 10px 14px 6px 14px;
    margin-bottom: -1px;
    font-size: 15px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--color-blue, #005e6a);
    border-bottom: 2px solid transparent;
    cursor: pointer;
    transition: color .2s, border-color .2s;
    user-select: none;
}

.mk-tab:hover {
    color: var(--primary);
}

.mk-tab-pane {
    display: none;
}

/* EVERY TAB KEY IS NAMED HERE, THREE TIMES OVER, AND HAS TO BE.
 *
 * The switch is `.mk-tab-input--x:checked ~ .mk-tab-pane--x`, which pairs one
 * input with one pane -- and CSS cannot correlate two arbitrary selectors, so
 * there is no way to write it once for all keys. A tab added to mkTabGroup()
 * without a line in each of the four lists below draws, does nothing when
 * pressed, and reports no error anywhere.
 *
 * Six keys today: coverage, breakdown and board from renderMarketplaceAi();
 * images, videos and files from renderMarketplaceMedia(). */
.mk-tab-input--coverage:checked ~ .mk-tab-bar .mk-tab--coverage,
.mk-tab-input--breakdown:checked ~ .mk-tab-bar .mk-tab--breakdown,
.mk-tab-input--board:checked ~ .mk-tab-bar .mk-tab--board,
.mk-tab-input--images:checked ~ .mk-tab-bar .mk-tab--images,
.mk-tab-input--videos:checked ~ .mk-tab-bar .mk-tab--videos,
.mk-tab-input--files:checked ~ .mk-tab-bar .mk-tab--files {
    color: var(--primary);
    border-bottom-color: var(--primary);
}

.mk-tab-input--coverage:checked ~ .mk-tab-panes .mk-tab-pane--coverage,
.mk-tab-input--breakdown:checked ~ .mk-tab-panes .mk-tab-pane--breakdown,
.mk-tab-input--board:checked ~ .mk-tab-panes .mk-tab-pane--board,
.mk-tab-input--images:checked ~ .mk-tab-panes .mk-tab-pane--images,
.mk-tab-input--videos:checked ~ .mk-tab-panes .mk-tab-pane--videos,
.mk-tab-input--files:checked ~ .mk-tab-panes .mk-tab-pane--files {
    display: block;
}

/* The open tab closes the box when pressed again (js/functions.js), and says
   so the way the AI Extras tabs do: a caret pointing at what it will fold. */
.mk-tab-input--coverage:checked ~ .mk-tab-bar .mk-tab--coverage::after,
.mk-tab-input--breakdown:checked ~ .mk-tab-bar .mk-tab--breakdown::after,
.mk-tab-input--board:checked ~ .mk-tab-bar .mk-tab--board::after,
.mk-tab-input--images:checked ~ .mk-tab-bar .mk-tab--images::after,
.mk-tab-input--videos:checked ~ .mk-tab-bar .mk-tab--videos::after,
.mk-tab-input--files:checked ~ .mk-tab-bar .mk-tab--files::after {
    content: "\25B2";
    font-size: .7em;
    opacity: .8;
}

/* What a shut box says -- the tabs on a script's own summary page use the same
   words and size (.tabs-hint in css/ai-logline.css). The bar loses its bottom
   margin so the line sits close under the tabs it is about. */
.mk-tabs-hint {
    display: none;
    margin: 0;
    padding: 2px 2px 4px;
    font-size: 16px;
    color: var(--text-soft);
}

.mk-tabs:not(:has(.mk-tab-input:checked)) .mk-tabs-hint {
    display: block;
}

.mk-tabs:not(:has(.mk-tab-input:checked)) .mk-tab-bar {
    margin-bottom: 10px;
}

/* Keyboard focus shows on the tab it would change, since the radio itself
   is out of sight. */
.mk-tab-input--coverage:focus-visible ~ .mk-tab-bar .mk-tab--coverage,
.mk-tab-input--breakdown:focus-visible ~ .mk-tab-bar .mk-tab--breakdown,
.mk-tab-input--board:focus-visible ~ .mk-tab-bar .mk-tab--board,
.mk-tab-input--images:focus-visible ~ .mk-tab-bar .mk-tab--images,
.mk-tab-input--videos:focus-visible ~ .mk-tab-bar .mk-tab--videos,
.mk-tab-input--files:focus-visible ~ .mk-tab-bar .mk-tab--files {
    outline: 2px solid var(--primary);
    outline-offset: -2px;
    border-radius: 4px 4px 0 0;
}

/* ---- the Media block's own furniture ------------------------------------ */

/* How many of each, on the tab itself. The count is the reason to press one --
   "Images 6" is worth a click and "Images" on its own is a guess -- and it is
   the same device the AI Extras tabs use on a script's own summary page.

   GREY AT REST, like .ai-tab-count in css/ai-logline.css. It was
   --primary-dim behind --primary, which is what that pill looks like when its
   tab is OPEN -- so on a public page every count sat there looking selected
   and the one actually selected had nothing to distinguish it. The same
   numbers, on the same kind of strip, should not mean different things on two
   pages. */
.mk-tab-count {
    display: inline-block;
    min-width: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--border, #e2e2e2);
    color: var(--text-muted, #6b6b6b);
    font-size: .78em;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
    vertical-align: 1px;
}

/* ONE TAB'S COUNT, NOT EVERY TAB'S.
 *
 * This was `.mk-tab-input:checked ~ .mk-tab-bar .mk-tab .mk-tab-count`, which
 * reads as "any checked input, then any count in the bar" -- so opening ANY
 * tab turned EVERY count primary at once. Combined with the resting colour
 * above, that is why they all looked active.
 *
 * Paired per key, the way every other rule in this file's tab block is, and
 * for the same reason: CSS cannot correlate two arbitrary selectors, so each
 * input has to name the tab it belongs to. Only the three media tabs can
 * carry a number -- coverage, breakdown and board are never counted -- so
 * only those three are listed. A fourth counted tab needs a line here. */
.mk-tab-input--images:checked ~ .mk-tab-bar .mk-tab--images .mk-tab-count,
.mk-tab-input--videos:checked ~ .mk-tab-bar .mk-tab--videos .mk-tab-count,
.mk-tab-input--files:checked ~ .mk-tab-bar .mk-tab--files .mk-tab-count {
    background: var(--primary);
    color: #fff;
}

/* NO .media-video-grid RULE HERE, AND THAT IS THE FIX.
 *
 * There was one: repeat(auto-fit, minmax(280px, 1fr)), on the reasoning that a
 * video wants room to be watched. Wrong twice over. css/dashboard.css already
 * defines that class as repeat(3, 1fr) with its own 2-up and 1-up breakpoints,
 * and it loads on the public link as well as the dashboard -- so this was a
 * second opinion silently overriding the first, and the answer it gave was a
 * video at nearly full page width.
 *
 * Small is right. A reader scanning a listing wants to see how many there are
 * and what they look like; a video they want to watch has a fullscreen button
 * of its own, which is a better full size than anything a grid can give it.
 *
 * .media-video-item and its caption below are new and belong here. The grid
 * they sit in does not.
 */
.media-video-item video {
    width: 100%;
    border-radius: 6px;
    display: block;
    background: #000;
}

.media-video-title {
    margin: 6px 0 0;
    font-size: 14px;
    color: var(--text-soft);
}

/* Files as a list, not a grid. A file is a name and a size -- there is nothing
   to look at, so there is nothing to arrange in columns, and a list reads down
   the way a list of documents should. */
.media-file-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.media-file-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-light);
    color: var(--text-dark);
    text-decoration: none;
    transition: border-color .12s, background .12s;
}

.media-file-item:hover {
    border-color: var(--primary);
    background: #fff;
}

.media-file-icon {
    flex: none;
    font-size: 22px;
    color: var(--primary);
}

/* min-width:0 so a long file name ellipsises instead of pushing the size off
   the right-hand edge of the row. */
.media-file-text {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
}

.media-file-name {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.media-file-desc {
    font-size: 13px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.media-file-size {
    flex: none;
    font-size: 13px;
    color: var(--text-muted);
}

@media (max-width: 600px) {
    .mk-tab {
        padding: 9px 8px;
        font-size: 15px;
    }
}

/* The board in its tab. .sb-host gives it the viewport's height less the
   header, which is right for a board that is the whole page; inside a box on
   a page it is a window onto the board instead, tall enough to work in. */
.mk-board.sb-host {
    height: 72vh;
    min-height: 460px;
    border-radius: 6px;
    overflow: hidden;
}

.mk-board-wait {
    margin: 0;
    padding: 20px;
    color: var(--text-muted);
}

/* ---- the board in a popup, from a Library card's board icon -------------

   z-index 900: over the site header (500 at most) and under #modal360
   (1000), because a scene on the board opens in that modal and has to land on
   top of this. See openMarketplaceBoard() in js/dashboard.js. */
.mk-board-pop {
    position: fixed;
    inset: 0;
    z-index: 900;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, .6);
}

.mk-board-pop-panel {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 1400px;
    height: 100%;
    background: var(--bg-white, #fff);
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 10px 40px rgba(0, 0, 0, .4);
}

.mk-board-pop-head {
    flex: none;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px 10px 18px;
    border-bottom: 1px solid var(--border);
}

.mk-board-pop-title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 18px;
    font-weight: 700;
    color: var(--text-dark);
}

.mk-board-pop-title i {
    margin-right: 6px;
    color: var(--primary);
}

.mk-board-pop-close {
    flex: none;
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: 50%;
    font-size: 20px;
    color: var(--text-soft);
    background: transparent;
    cursor: pointer;
}

.mk-board-pop-close:hover {
    background: var(--btn-bg-light, #eef1f5);
}

/* The board takes what the head leaves. sb-host-fill wants a parent with a
   definite height, which the flex column gives it. */
.mk-board-pop-body {
    flex: 1 1 auto;
    min-height: 0;
}

@media (max-width: 600px) {
    .mk-board-pop {
        padding: 0;
    }

    .mk-board-pop-panel {
        border-radius: 0;
    }
}
/* ---- the author's switch, on a script's own detail page ----------------- */
.mk-switch-block {
    margin-bottom: 14px;
}

.mk-switch {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 6px;
    cursor: pointer;
    width: fit-content;
}

/* The checkbox itself is taken out of sight rather than out of the document:
   removed with display:none it stops being focusable, and the switch would
   then be unreachable by keyboard. */
.mk-switch input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.mk-switch-track {
    position: relative;
    width: 42px;
    height: 22px;
    flex: none;
    border-radius: 11px;
    background: var(--border, #ccd2dc);
    transition: background .15s;
}

.mk-switch-knob {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    transition: transform .15s;
}

.mk-switch input:checked + .mk-switch-track {
    background: var(--success, #1ee0ac);
}

.mk-switch input:checked + .mk-switch-track .mk-switch-knob {
    transform: translateX(20px);
}

/* Visible focus, because the input it belongs to has none of its own now. */
.mk-switch input:focus-visible + .mk-switch-track {
    outline: 2px solid var(--primary, #e85347);
    outline-offset: 2px;
}

.mk-switch-text {
    font-size: 15px;
    color: var(--text-soft);
}

.mk-switch input:disabled + .mk-switch-track {
    opacity: .5;
}

/* A switch that is set but cannot be moved: a lapsed membership, where the
   flag is on and the screenplay is not being shown. The label must not offer
   the pointer that says it can be clicked -- .mk-switch sets one for the
   ordinary case, and a disabled input inside a label the cursor still invites
   you to press is worse than no cursor at all. */
.mk-switch--locked {
    cursor: default;
}

/* The same slider, in a coverage report's action row.
 *
 * .cv-actions is a row of controls -- publish, delete -- and the switch joins
 * them rather than sitting above on a line of its own: all three are the author
 * deciding something about this one report, and separating one of them would
 * read as it being a different kind of thing.
 *
 * margin-top:0 undoes the 6px the switch carries on the script detail page,
 * where it follows a label; here it has a row to line up with. */
.cv-actions .cv-member-switch {
    margin-top: 0;
    margin-right: 4px;
}

.cv-actions .cv-member-switch .mk-switch-text {
    font-size: 14px;
    cursor: help;
}

.mk-switch-warn,
.mk-switch-upsell {
    margin: 8px 0 0;
    font-size: 14px;
    line-height: 1.35;
    color: var(--text-soft);
}

.mk-switch-warn i {
    color: var(--warning, #f4bd0e);
    margin-right: 4px;
}

.mk-switch-upsell i {
    margin-right: 4px;
}

/* ---- narrow ------------------------------------------------------------- */

/* One pager on a phone, not two.
 *
 * The head is already wrapping at this width -- the count on one line, the
 * switch on the next -- and a pager of up to eleven buttons between them takes
 * two more, so a reader would scroll past four lines of furniture before
 * reaching the first card. The pager at the foot is untouched and is the one
 * that matters on a small screen anyway, since getting there means having
 * scrolled through the page already. */
@media (max-width: 640px) {
    .mk-list-tools .mk-pager {
        display: none;
    }
}

@media (max-width: 900px) {

    /* The WALL only. The listing used to collapse here too and now waits until
       700 -- see the block after this one. They were together because both are
       a narrow column beside a wide one, but they are narrow for different
       reasons: this one holds the filters, which have a toggle of their own
       appearing at this same width, and that one holds a poster, which is
       perfectly readable in half of a 760px window. */
    .mk-wrap {
        grid-template-columns: minmax(0, 1fr);
    }

    .mk-filter-toggle {
        display: flex;
        align-items: center;
        gap: 8px;
        width: 100%;
        padding: 10px 12px;
        border: 1px solid var(--border-color, #e5e7eb);
        border-radius: 8px;
        background: var(--card-bg, #fff);
        font: inherit;
        cursor: pointer;
    }

    .mk-filter-caret {
        margin-left: auto;
        transition: transform .15s;
    }

    .mk-filter-toggle.open .mk-filter-caret {
        transform: rotate(180deg);
    }

    /* Collapsed by default at this width and opened by the button above. It
       keeps its place in the flow either way -- the whole reason the panel is
       not a fixed sidebar. */
    .mk-filters {
        display: none;
        position: static;
        max-height: none;
    }

    .mk-filters.open {
        display: block;
    }
}


/* THE LISTING, ONE COLUMN AT LAST.
 *
 * 700 rather than the 900 the wall collapses at. Two things bought the extra
 * 200px: the listing is a full-width page now -- FULL_WIDTH_PAGES in
 * js/dashboard.js hides the sidebar for it, the same as an author sees on
 * their own summary -- so the window it is laid out in is about 250px wider
 * than it was; and a 260px poster beside a logline is a perfectly good use of
 * a 760px window, where a filter panel beside a wall of cards is not.
 *
 * Below this the poster stops being a column and becomes a header, at a size
 * that does not take the whole screen before the logline is reached. */
@media (max-width: 700px) {

    .mk-listing-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Centred, not left against the edge. In two columns the poster sits in a
       column of its own and its left edge lines up with everything below it;
       stacked, that same edge reads as a picture that failed to fill the row.
       margin-inline is what centres it, because max-width has already stopped
       it being full width. */
    .mk-listing-poster {
        max-width: 220px;
        margin-inline: auto;
    }

    /* The title and its episode line, centred over the centred poster.
     *
     * Only these two. Everything under them -- the logline, the synopsis, the
     * genres -- is prose or a row of chips, and centred prose is harder to
     * read: the eye loses the left edge it returns to on every line. A title
     * is one or two lines and is a label rather than something to read
     * through, so it can sit over the picture it names. */
    .mk-listing-title,
    .mk-listing-episode {
        text-align: center;
    }

    /* And gone altogether when it is not a real poster.
     *
     * A script with nothing uploaded gets a stand-in, which is worth a column
     * beside the words -- it fills a space that would otherwise be empty and
     * it says the listing is a screenplay. Stacked, it is a screenful of
     * generic artwork between the title and the logline, which is the last
     * place a reader on a phone can afford one. The class is put on by
     * renderMarketplaceListing(), off the same img_url that decides whether
     * the poster opens. */
    .mk-listing-poster--none {
        display: none;
    }
}

/* What a listing says to somebody who has already asked to read it.

   Not a button: a second request is refused by the unique key and by
   requestScriptAccess.php, so a control here would be one that turns them
   down. It sits in the same row the buttons do and is sized to be read
   alongside them rather than to be pressed. */
.mk-req-state {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 15px;
    font-weight: 600;
}

.mk-req-pending {
    color: var(--text-soft);
}

/* Stated, not warned about. A decline is the author exercising a choice the
   feature exists to give them, and a red alert would read as a fault. */
.mk-req-declined {
    color: var(--text-muted);
}

/* The same three states as a mark on the wall's cards -- see
   marketplaceRequestMark(). Sized with the extras beside it rather than with
   the line above: on a card this is one icon among several, and the byline it
   sits on has a fixed floor that a larger glyph would push about.

   Coloured, unlike the line on the listing page, because here there is no
   sentence to read. Three icons in one colour would need learning; a pending
   amber, an approved green and a grey no are read without being learned. */
.mk-req-mark {
    display: inline-flex;
    align-items: center;
    font-size: 19px;
}

.mk-req-mark--pending {
    color: var(--warning);
}

.mk-req-mark--approved {
    color: var(--success);
}

/* Grey, not red, for the same reason .mk-req-declined is: the author said no,
   which is the feature working rather than something going wrong. */
.mk-req-mark--declined {
    color: var(--text-muted);
}

/* An extras icon that carries a number -- the cast count, today.

   Its own span so the number sits against its icon rather than being pushed to
   the far end by the byline row's gap. */
.mk-extra {
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.mk-extra-count {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-soft);
}

/* ── THE COVERAGE SCORE, IN THE CARD'S CORNER ─────────────────────────────

   What a browser is scanning the Library for. It used to sit at the
   right-hand end of the byline among the icons that say what a screenplay
   has -- the right place for "has images", the wrong one for the single
   number that decides whether somebody opens the card at all.

   The colours are .cv-verdict--{class} from css/ai-logline.css, the same five
   the report itself and the Browse Coverage cards use: a Recommend is green
   wherever it appears. Those rules set the background and the text colour, and
   the border here takes that text colour through currentColor -- which is what
   makes the thick edge read as the verdict without naming the five colours a
   second time in this file. */
.mk-cov-box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 56px;
    padding: 6px 10px;
    border: 3px solid currentColor;
    border-radius: 8px;
    cursor: pointer;
    /* The verdict classes are written for a wide bar inside the report, where
       the word and the number sit at opposite ends. */
    gap: 0;
}

.mk-cov-box-score {
    font-size: 20px;
    font-weight: 800;
    line-height: 1;
    letter-spacing: -.5px;
}

/* The AI's box and our analysts', one above the other, each with its icon
   inside -- a wand or the people glyph -- to say whose score it is (Ben,
   2026-09-30). Either may be missing. */
.mk-cov-boxes {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}

.mk-cov-boxes .mk-cov-box {
    gap: 6px;
    min-width: 70px;
    justify-content: space-between;
}

.mk-cov-box-icon {
    font-size: 13px;
    opacity: .8;
}

/* A First Act Review has a verdict and no score: the icon alone, a little
   larger, in a box the width of the others. */
.mk-cov-box--pro:not(:has(.mk-cov-box-score)) {
    justify-content: center;
    min-height: 36px;
}

.mk-cov-box--pro:not(:has(.mk-cov-box-score)) .mk-cov-box-icon {
    font-size: 17px;
}

/* On a full-width row the card is short, so the box sits beside the poster
   rather than over it. */
.dash-card-wide .mk-cov-box {
    min-width: 50px;
    padding: 4px 8px;
}

.dash-card-wide .mk-cov-box-score {
    font-size: 20px;
}

.dash-card-wide .mk-cov-boxes {
    gap: 4px;
}

.dash-card-wide .mk-cov-boxes .mk-cov-box {
    min-width: 62px;
}


/* ── FAVORITES ────────────────────────────────────────────────────────────

   The heart -- see renderFavoriteHeart() in includes/favorites.php. A bare
   heart among the extras on a Library card, sized with .mk-req-mark beside it;
   a labelled .open-script-btn on the listing page and the script summary bar.
   Outlined and muted when off, filled and red when on: the one colour on the
   card that means "you did this". */
.fav-heart {
    font-family: inherit;
}

.fav-heart--card {
    display: inline-flex;
    align-items: center;
    padding: 0;
    border: none;
    background: none;
    font-size: 19px;
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.15s, transform 0.15s;
}

.fav-heart--card:hover {
    color: var(--danger);
    transform: scale(1.12);
}

.fav-heart.is-on i {
    color: var(--danger);
}

/* On the button, the icon takes the colour and the button keeps its own --
   it is one of a row of the same buttons, and a red one would read as Delete. */
.fav-heart--button:hover.is-on i {
    color: white;
}

/* The author's line under the Library switch on the summary page. */
.fav-count {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 14px;
    font-size: 14px;
    color: var(--text-muted);
}

.fav-count i {
    color: var(--danger);
}
