/*
 * Listing table of a back office section — Figma "Frame 757" (4687:21019).
 *
 * The maquette draws it once, on the "Phrase promotionnelle" screen, and the ten other sections
 * reuse it: a grey header row, then white rows separated by a hairline, 56px tall, each cell padded
 * by Spacing/xs left and right. The whole block is clipped by a 4px radius, so the header corners
 * are rounded without the cells having to be.
 *
 * The vertical padding is tighter than Spacing/xs: the actions column carries a row of 32px
 * icon-only controls (Modifier/Supprimer, and the directory's edit/confirm/cancel), and 2×16px of
 * padding around them alone already exceeds the 56px row — 12px is the most either side can take
 * without pushing the row past what the maquette draws.
 *
 * It is a real <table>: the content is tabular, a screen reader must announce the column of a cell,
 * and the "Actions" cell carries forms rather than links.
 */

/* The table is the one block of a back office screen that can outgrow the column, so it scrolls
 * inside its own box instead of stretching the frame and pushing the rail off-screen. */
.mo-admin-table__scroll {
    overflow-x: auto;
    border-radius: var(--mo-radius-sm);
}

.mo-admin-table {
    width: 100%;
    border-collapse: collapse;
    background-color: var(--mo-surface-default-white);
}

.mo-admin-table__head {
    background-color: var(--mo-surface-default);
}

.mo-admin-table th,
.mo-admin-table td {
    /* 56px is what the maquette draws, and it is not a step of the Scale collection — Figma writes
     * it literally here too (`h-[56px]`), so it is written literally rather than rounded to the
     * 48px of Scale/600. 12px is likewise not a step of the Spacing collection — see the comment
     * atop this file. */
    height: 56px;
    padding: 12px var(--mo-spacing-xs);
    text-align: left;
    vertical-align: middle;
}

.mo-admin-table th {
    color: var(--mo-text-heading);
    font-size: var(--mo-font-size-h5);
    font-weight: var(--mo-font-weight-h5);
    line-height: var(--mo-line-height-h5);
    white-space: nowrap;
}

.mo-admin-table td {
    border-bottom: 1px solid var(--mo-border-default-medium);
    color: var(--mo-text-body);
    font-size: var(--mo-font-size-body-sm);
    /* The maquette sets the body cells in SemiBold, one weight above the portal listings. */
    font-weight: var(--mo-font-weight-semibold);
    line-height: var(--mo-line-height-body-sm);
}

/* A long single-line value is cut rather than allowed to widen the column. */
.mo-admin-table__ellipsis {
    display: block;
    overflow: hidden;
    max-width: 60ch;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * "Description" column — §§ 4.2.1, 4.5.1, 4.7.1, 4.8.1 and 4.10.1 all ask for one, and the maquette
 * draws none, so the rule is set once here rather than five times: a single cut line, narrower than
 * a title so the two never compete for the row, with the full text on the cell's `title` attribute.
 *
 * Deliberately not a two-line clamp: the rows of the maquette are 56px tall, and a table whose rows
 * grow with their longest description stops being scannable.
 */
.mo-admin-table__description {
    display: block;
    overflow: hidden;
    max-width: 32ch;
    color: var(--mo-text-body);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A date range is one value: the maquette prints "01/01/2026 - 01/01/2027" on a single line. */
.mo-admin-table__nowrap {
    white-space: nowrap;
}

.mo-admin-table__actions {
    display: flex;
    align-items: center;
    gap: 10px;
}

/*
 * The delete control is a <form>, not the <a> the edit badge is. Safari does not shrink a bare
 * <form> to its content when it is a flex item — it keeps the form's block-level intrinsic size,
 * which renders the button oversized and off the row's vertical center. Making it a flex item
 * itself (and clearing the UA margin) sizes it to its one child exactly like the edit badge.
 */
.mo-admin-table__delete {
    display: inline-flex;
    margin: 0;
}

/*
 * The directory's "Site"/"URL Facebook"/"URL Instagram" columns print the portal's `IconButton`
 * (globe/Facebook/Instagram, plus the pencil/confirm/cancel of the inline edit) — 42px there, sized
 * for the member portal rather than for this 56px row. Brought down to the 32px every other
 * icon-only control of a back office table already uses (`.mo-admin-badge--icon-only`), for the
 * same row height and the same visual weight as Modifier/Supprimer.
 */
.mo-admin-table .mo-button--icon-only {
    width: var(--mo-scale-400);
    height: var(--mo-scale-400);
}

/* Thumbnail of an image row — the banners and the coverings show what they publish. */
.mo-admin-table__thumbnail {
    display: block;
    width: var(--mo-scale-1000);
    height: var(--mo-scale-500);
    border-radius: var(--mo-radius-sm);
    object-fit: cover;
}

/*
 * Empty state. Not in the maquette, which only draws a filled table: a section with no row yet must
 * still say so rather than show a header above nothing.
 */
.mo-admin-table__empty {
    color: var(--mo-text-placeholder);
    font-weight: var(--mo-font-weight-regular);
}

/*
 * Sort control of a header cell — § 2, « Toutes les colonnes sont triables ».
 *
 * A link, not a button: the state lives in the URL, so the header of a sorted table is something the
 * group can bookmark and send on, and the whole feature works with no JavaScript.
 */
.mo-admin-table__sort {
    display: inline-flex;
    align-items: center;
    color: inherit;
    gap: 4px;
    text-decoration: none;
}

.mo-admin-table__sort:hover {
    text-decoration: underline;
}

.mo-admin-table__sort:focus-visible {
    outline: 2px solid var(--mo-border-action);
    outline-offset: 2px;
}

/* The chevron of a column that is not the one being sorted on is a hint, not a statement. */
.mo-admin-table__sort-icon {
    width: 16px;
    height: 16px;
    flex: none;
    opacity: 0.3;
}

.mo-admin-table__sort--on .mo-admin-table__sort-icon {
    opacity: 1;
}

/*
 * Filter form — § 2, « Possibilité de filtrer sur toutes les colonnes des tableaux ».
 *
 * A standalone form above the table rather than a row inside it — see `_filters.html.twig` for why
 * it cannot wrap the table. Its fields reuse the back office form controls (`.mo-admin-form__*` of
 * `admin-form.css`) so a filter field looks like any other; this is only the panel around them.
 *
 * Rendered by the server and folded afterwards by the `table-filters` controller, so a browser that
 * runs no JavaScript simply gets an open form rather than an empty table it cannot narrow.
 */
.mo-admin-table-filters {
    display: flex;
    flex-direction: column;
    gap: var(--mo-spacing-sm);
    padding: var(--mo-spacing-sm);
    border-radius: var(--mo-radius-sm);
    background-color: var(--mo-surface-default);
}

/*
 * `display: flex` above ties with the user agent rule for [hidden] on specificity, and wins on
 * source order: the `table-filters` controller folds the form by setting this attribute, and
 * without the override here it would keep rendering as an open flex box regardless.
 */
.mo-admin-table-filters[hidden] {
    display: none;
}

/*
 * "Position" cell of the four tables § 4 gives a `C9` drag handle: the handle, then the number it
 * stands for. The number stays visible — it is what the group edits when the drag is not available,
 * and it is the only thing that says where a row is without counting from the top.
 */
.mo-admin-table__position {
    white-space: nowrap;
}

.mo-admin-table__handle {
    display: inline-flex;
    align-items: center;
    margin-right: 4px;
    color: var(--mo-text-placeholder);
    cursor: grab;
    vertical-align: middle;
}

.mo-admin-table__handle:active {
    cursor: grabbing;
}

.mo-admin-table__handle-icon {
    width: 18px;
    height: 18px;
}

/* The row being dragged, and the gap it leaves behind — the two classes SortableJS adds. */
.sortable-ghost {
    opacity: 0.4;
}

.sortable-chosen .mo-admin-table__handle {
    color: var(--mo-text-action);
}

/*
 * "Site", "URL Facebook" and "URL Instagram" cells of the "Annuaire" directory (§ 4.11) — no
 * maquette draws this, the section having none of its own. `inline_link_edit_controller.js`
 * toggles between the value and the form; the pencil, confirm and cancel buttons reuse
 * `.mo-admin-badge` rather than a parallel button of their own.
 */
.mo-admin-editable-url {
    display: flex;
    align-items: center;
    gap: var(--mo-spacing-xxs);
}

.mo-admin-editable-url__value {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--mo-spacing-xxxs);
    min-width: 0;
}

/* Same cascade tie as .mo-admin-editable-url__form[hidden] below — hides the value while editing. */
.mo-admin-editable-url__value[hidden] {
    display: none;
}

.mo-admin-editable-url__form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--mo-spacing-xxxs);
}

/*
 * `display: flex` above ties with the user agent rule for [hidden] on specificity, and wins on
 * cascade order — restated here so the form stays hidden until inline_link_edit_controller.js#edit
 * clears the attribute, the same pattern as .mo-admin-form__group[hidden] and .mo-button[hidden].
 */
.mo-admin-editable-url__form[hidden] {
    display: none;
}

.mo-admin-editable-url__input {
    width: 100%;
    min-width: 180px;
    padding: var(--mo-spacing-xxxs) var(--mo-spacing-xxs);
    border: 1px solid var(--mo-border-default-medium);
    border-radius: var(--mo-radius-sm);
    color: var(--mo-text-body);
    font-family: inherit;
    font-size: var(--mo-font-size-body-sm);
}

.mo-admin-editable-url__input:focus-visible {
    outline: 2px solid var(--mo-border-action);
    outline-offset: 1px;
}

.mo-admin-editable-url__error {
    width: 100%;
    color: var(--mo-border-error);
    font-size: var(--mo-font-size-caption);
}
