/* ======================================================================
 * Sepiline — the thin layer on top of Metronic 8
 * ----------------------------------------------------------------------
 * House rule: if the Metronic documentation
 * (https://preview.keenthemes.com/html/metronic/docs/) has a component or
 * a utility for it, the markup uses that and nothing is written here.
 *
 * So this file holds only the four things Metronic genuinely does not
 * cover, plus a short list of fixes to Metronic itself:
 *
 *   1. Glyphs missing from the bundled keenicons set
 *   2. The stacked-card responsive table (label + value per row)
 *   3. Bidirectional-text handling for a fa/en app
 *   4. Small gaps: tabular figures, sticky mobile form actions
 *   5. Fixes: keenicon colour inside a symbol, select2 duplicates
 *
 * Every colour, radius and spacing value comes from Metronic's own
 * `--bs-*` variables, which `[data-bs-theme=dark]` already re-points, so
 * dark mode needs no counterpart rule anywhere below.
 *
 * No animation, no transitions, no hover transforms — by design.
 * ====================================================================== */

/* ======================================================================
 * 1. Glyphs missing from this keenicons build
 * ----------------------------------------------------------------------
 * `ki-microphone-2`, `ki-play` and `ki-pause` are referenced by the audio
 * controls but are NOT among the 575 glyphs in plugins.bundle.css, so they
 * rendered as blank boxes. These draw the glyph from an SVG mask: it takes
 * `currentColor`, scales with `font-size` (so `fs-*` still works), and
 * needs no icon font. `common/tests_icons.py` fails the build if a glyph
 * outside the bundle is referenced again.
 * ====================================================================== */

.app-icon {
    display: inline-block;
    inline-size: 1em;
    block-size: 1em;
    vertical-align: -0.125em;
    background-color: currentColor;
    -webkit-mask: var(--app-icon) center / contain no-repeat;
    mask: var(--app-icon) center / contain no-repeat;
}

/*
 * The brand lockup reads the same way round in both languages: the mark on the
 * left of the name.
 *
 * RTL flips flex order, which parked the mark to the *right* of "Sepiline" on
 * every Persian screen. A logo is a picture of a name, not a sentence — it is
 * not mirrored when the page is, any more than the wordmark's letters are. One
 * declaration does it, so the two lockups (the sidebar and the phone header) no
 * longer need `order-1` / `order-2` to argue with the page direction.
 */
.app-brand {
    direction: ltr;
}

.app-icon-mic {
    --app-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 3a3 3 0 0 1 3 3v5a3 3 0 0 1-6 0V6a3 3 0 0 1 3-3Zm7 8a7 7 0 0 1-6 6.93V21h-2v-3.07A7 7 0 0 1 5 11h2a5 5 0 0 0 10 0h2Z'/%3E%3C/svg%3E");
}

.app-icon-play {
    --app-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M8 5.14v13.72a1 1 0 0 0 1.54.84l10.29-6.86a1 1 0 0 0 0-1.68L9.54 4.3A1 1 0 0 0 8 5.14Z'/%3E%3C/svg%3E");
}

.app-icon-pause {
    --app-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M7 4h3.2v16H7zm6.8 0H17v16h-3.2z'/%3E%3C/svg%3E");
}

/*
 * No RTL rule for the play triangle.
 *
 * There was one, and it mirrored the icon: a comment saying a play triangle
 * must not be flipped, over a `scaleX(-1)` that flipped it. Nothing in this app
 * mirrors an icon, so the rule had nothing to undo — it just pointed the
 * triangle backwards on every Persian screen. Play is a media convention, not a
 * reading direction: it points the way the tape runs, in every language.
 */

/* ======================================================================
 * 2. Stacked-card responsive tables
 * ----------------------------------------------------------------------
 * Metronic's answer to a narrow screen is `.table-responsive`, i.e.
 * sideways scrolling. These rows carry too many columns for that to read
 * on a phone, so below `md` each row becomes a card. Both variants are
 * driven by `data-label` on every <td> — no duplicate mobile markup:
 *
 *   .table-mobile-cards   read-only rows  -> label beside value
 *   .table-entry-cards    editable rows   -> label above a full-width control
 * ====================================================================== */

@media (max-width: 767.98px) {
    .table-mobile-cards thead,
    .table-entry-cards thead {
        display: none;
    }

    .table-mobile-cards tbody tr,
    .table-entry-cards tbody tr {
        display: block;
        border: 1px solid var(--bs-border-color);
        border-radius: var(--bs-border-radius);
        margin-bottom: 0.75rem;
        padding: 0.75rem 1rem;
        background-color: var(--bs-card-bg);
    }

    .table-mobile-cards tbody td,
    .table-entry-cards tbody td {
        border: none;
        padding-top: 0.25rem;
        padding-bottom: 0.25rem;
    }

    /*
     * `data-autodir` puts dir="rtl" on cells holding Persian text. In a
     * stacked card that would mirror the row too, so the label would jump
     * sides between rows. Pin the box direction to the page and let
     * `unicode-bidi: plaintext` resolve each value's own reading direction.
     */
    .table-mobile-cards tbody td {
        display: flex;
        justify-content: space-between;
        align-items: flex-start;
        gap: 0.75rem;
        text-align: start;
        direction: inherit;
        unicode-bidi: plaintext;
    }

    .table-entry-cards tbody td {
        display: block;
        direction: inherit;
    }

    .table-mobile-cards tbody td::before,
    .table-entry-cards tbody td::before {
        content: attr(data-label);
        font-size: 0.85rem;
        font-weight: 600;
        color: var(--bs-gray-500);
        flex-shrink: 0;
    }

    .table-entry-cards tbody td::before {
        display: block;
        margin-bottom: 0.25rem;
    }

    /*
     * A stacked card is a label and its value on one line, so a cell that is
     * centred or pushed to the end edge in the table has nowhere useful to go
     * here: `justify-content` already places the value opposite its label.
     * `!important` because the utilities being undone carry it themselves.
     */
    .table-mobile-cards tbody td.text-center,
    .table-mobile-cards tbody td.text-end,
    .table-entry-cards tbody td.text-center,
    .table-entry-cards tbody td.text-end {
        text-align: start !important;
    }

    .table-entry-cards tbody td audio {
        inline-size: 100%;
        margin-bottom: 0.5rem;
    }

    /* Cells with no label (spacers, action columns, empty states). */
    .table-mobile-cards tbody td[data-label=""]::before,
    .table-entry-cards tbody td[data-label=""]::before,
    .table-mobile-cards tbody td:not([data-label])::before,
    .table-entry-cards tbody td:not([data-label])::before {
        content: none;
    }

    /* An empty-state cell must not inherit the row chrome. */
    .table-mobile-cards tbody tr:has(> td > .card),
    .table-entry-cards tbody tr:has(> td > .card) {
        border: none;
        padding: 0;
        background: transparent;
    }
}

/* ======================================================================
 * 3. Bidirectional text
 * ====================================================================== */

/*
 * A cell can hold English or Persian. `unicode-bidi: plaintext` lets each
 * value pick its own reading direction without the row flipping.
 */
[data-autodir] {
    unicode-bidi: plaintext;
}

/*
 * toastr reserves space for its icon on the physical left and paints the icon
 * there — even in the RTL bundle — so in Persian the icon lands after the text
 * and the words are squeezed into what is left. Mirror both.
 */
html[dir="rtl"] #toastr-container > div {
    padding: 15px 50px 15px 15px;
    background-position: calc(100% - 15px) center;
}

/* Metronic's select2 build shows its clear affordance twice in RTL. */
.select2-container--bootstrap5 .select2-selection__clear,
.select2-selection__clear {
    display: none !important;
}

/*
 * The tick on the chosen option is pinned with a physical `right` — in the
 * RTL bundle too, which the mirroring pass missed. In Persian the text also
 * starts on the right, so the two land on top of each other. Both edges are
 * written logically here, so the tick sits opposite the text in either
 * language: physical right in English, physical left in Persian. `auto` on
 * the near edge is what clears the bundle's own `right`, and the option
 * reserves room for the tick so a long label never reaches it.
 */
.select2-container--bootstrap5 .select2-dropdown .select2-results__option.select2-results__option--selected {
    padding-inline: 1.25rem 2.75rem;
}

.select2-container--bootstrap5 .select2-dropdown .select2-results__option.select2-results__option--selected::after {
    inset-inline-start: auto;
    inset-inline-end: 1.25rem;
}

/* ======================================================================
 * 4. Small gaps in the utility set
 * ====================================================================== */

/* Metronic has no tabular-figures utility; columns of numbers need one. */
.tabular {
    font-variant-numeric: tabular-nums;
}

/*
 * A long form on a phone must not hide its save button below the fold.
 * From `md` up the button row sits inline again, so this is mobile-only.
 */
@media (max-width: 767.98px) {
    .sticky-actions {
        position: sticky;
        bottom: 0;
        z-index: 20;
        background-color: var(--bs-card-bg);
        border-top: 1px solid var(--bs-border-color);
        padding-top: 0.75rem;
        padding-bottom: 0.75rem;
    }

    /* Comfortable touch targets for the dense action buttons in tables. */
    .btn.btn-sm,
    .btn-icon.btn-sm {
        min-height: 2.5rem;
    }

    .btn-icon.btn-sm {
        min-width: 2.5rem;
    }
}

/* A tab strip scrolls rather than wraps on a narrow screen. */
.nav-line-tabs.flex-nowrap {
    scrollbar-width: none;
}

.nav-line-tabs.flex-nowrap::-webkit-scrollbar {
    display: none;
}

/* Full labels on the quiz readiness chips only when there is room. */
.readiness-chip .chip-full {
    display: none;
}

@media (min-width: 768px) {
    .readiness-chip .chip-short { display: none; }
    .readiness-chip .chip-full { display: inline; }
}

/* ======================================================================
 * 5. Fixes to Metronic itself
 * ====================================================================== */

/*
 * Keenicons hard-codes its own grey on every `.ki-*`, so an icon placed in
 * a tinted `.symbol-label` stayed grey whatever colour the label carried.
 * Let it inherit instead — `bg-light-primary` + `text-primary` then works
 * exactly as the docs describe.
 */
.symbol-label > i,
.symbol-label > .app-icon,
.btn > .app-icon {
    color: inherit;
}

/*
 * Metronic positions a button's icon with `.btn > i { vertical-align: middle }`,
 * which aligns the glyph to half the *font's* x-height rather than to the
 * button. With the Latin face that lands within half a pixel of centre, so the
 * theme's own demos look right. With the Persian face — different ascenders,
 * different baseline — the icon rides 1.4 to 2.3px high: invisible on one
 * button, and a visible wobble across a toolbar of them.
 *
 * Aligning the button's own content sidesteps the font metrics entirely and
 * measures zero in both languages. It is the documented Bootstrap way to do
 * this (`d-inline-flex align-items-center`, which one button in the app
 * already carried); it lives here rather than on some fifty buttons so that
 * the next button added cannot bring the bug back.
 *
 * The selector asks for an icon, so a plain text button keeps its inline
 * layout. `.btn-icon` needs no exclusion: Metronic already gives those the
 * same three declarations.
 *
 * The last two selectors reach the same pairing one level down, inside the
 * `.indicator-label` of a button that swaps in a spinner while it works. They
 * spare an icon marked `d-block`, which is a deliberately *stacked* button —
 * the quiz's correct/wrong pair puts its glyph above the word, and flexing
 * that into a row would undo the layout rather than align it.
 *
 * One selector per icon kind, and `:has(> …)` rather than `:has(…)`, to keep
 * every one of them under three classes' worth of specificity. `:has()` is as
 * specific as its most specific argument, so the single rule this replaces
 * weighed exactly as much as the theme's own `.stepper.first [data-kt-stepper
 * -action=previous] { display: none }` and, being loaded later, beat it: a
 * wizard's "back" button stayed on screen on the first step. A fix to a
 * theme's typography should not be able to outvote the theme's behaviour.
 */
.btn:has(> i),
.btn:has(> svg),
.btn:has(> .app-icon),
.btn .indicator-label:has(> i:not(.d-block)),
.btn .indicator-label:has(> .app-icon:not(.d-block)) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* Bootstrap only outlines on :focus; keyboard users need :focus-visible. */
.btn:focus-visible,
a:focus-visible,
.menu-link:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

/*
 * The focused field.
 *
 * Metronic means to give a control a soft ring on focus, but its stylesheet
 * emits `box-shadow: false, 0 0 0 0.25rem …` — one invalid value voids the
 * whole declaration, so the ring never appeared. What was left was the outline
 * above, and a text box matches `:focus-visible` on a plain mouse click too:
 * every focused field wore two hard blue lines with a gap between them.
 *
 * One ring instead, drawn on the field itself, in both themes. The outline is
 * dropped only where this ring takes its place — buttons, links and menu items
 * keep theirs.
 */
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.22);
}

.form-control:focus-visible,
.form-select:focus-visible,
.form-check-input:focus-visible {
    outline: none;
}

/* The active sidebar item reads as active in both themes. */
.app-sidebar .menu-link.active .menu-icon,
.app-sidebar .menu-link.active .menu-title {
    color: var(--bs-primary);
}

/* ----------------------------------------------------------------------
 * The collapsed sidebar
 * ----------------------------------------------------------------------
 * Metronic collapses the sidebar by fading `.menu-content` and `.menu-title`
 * to `opacity: 0` — they keep their box, which is fine for a menu of plain
 * links but leaves a tall invisible gap wherever a section heading sits. It
 * also leaves each icon where the expanded layout put it: hard against the
 * start edge, and with no background on the active one, so the rail reads as
 * a scattered column of grey glyphs.
 *
 * The two selectors below are the two ways a sidebar can be collapsed: not
 * hoverable at all, or hoverable and not currently hovered. Metronic writes
 * the same pair for its own collapse rules.
 * ------------------------------------------------------------------- */

/*
 * Metronic lays the logo row out with `justify-content: space-between`, which
 * is right while the row holds two things — the mark at one end, the wordmark
 * at the other. Collapsed, the wordmark is hidden and `space-between` has
 * nothing left to space, so it parks the lone mark against the start edge:
 * 6.7px off the rail's centre line, and visibly out of step with the column of
 * menu icons beneath it, which Metronic does centre.
 */
[data-kt-app-sidebar-minimize="on"]:not([data-kt-app-sidebar-hoverable="true"]) .app-sidebar .app-sidebar-logo,
[data-kt-app-sidebar-minimize="on"][data-kt-app-sidebar-hoverable="true"] .app-sidebar:not(:hover) .app-sidebar-logo {
    justify-content: center;
}

/*
 * The footer credit has nowhere to go in a 75px rail. Metronic's own
 * `.app-sidebar-logo-default` hook would hide it, but that selector is scoped
 * to the logo row, so the footer needs saying here.
 *
 * `visibility`, not `display`: the footer is one of the two fixed rows that
 * the menu's scroll height is measured against, and that height is computed
 * once. Collapsing the row to nothing made the measurement 48px too generous,
 * so expanding the sidebar again pushed the credit off the bottom of the
 * screen until the next reload. Keeping the box reserves the same space in
 * both states, and an empty strip at the foot of the rail shows nothing.
 */
[data-kt-app-sidebar-minimize="on"]:not([data-kt-app-sidebar-hoverable="true"]) .app-sidebar .app-sidebar-footer,
[data-kt-app-sidebar-minimize="on"][data-kt-app-sidebar-hoverable="true"] .app-sidebar:not(:hover) .app-sidebar-footer {
    visibility: hidden;
}

/* A section heading has nothing to say without its label. */
[data-kt-app-sidebar-minimize="on"]:not([data-kt-app-sidebar-hoverable="true"]) .app-sidebar .menu-heading-row,
[data-kt-app-sidebar-minimize="on"][data-kt-app-sidebar-hoverable="true"] .app-sidebar:not(:hover) .menu-heading-row {
    display: none;
}

/*
 * In the rail the icon is the only thing carrying meaning, so it has to be
 * legible on its own — the expanded sidebar can afford a dim icon because the
 * label does the work.
 */
[data-kt-app-sidebar-minimize="on"]:not([data-kt-app-sidebar-hoverable="true"]) .app-sidebar .menu-link .menu-icon,
[data-kt-app-sidebar-minimize="on"][data-kt-app-sidebar-hoverable="true"] .app-sidebar:not(:hover) .menu-link .menu-icon {
    color: var(--bs-gray-600);
}

/*
 * "Which page am I on" also has to be carried by the icon. The highlight goes
 * on the icon rather than on the link: the link keeps its full expanded width
 * and is merely clipped by the 75px rail, so a background on it would run off
 * the edge — whereas Metronic already centres the icon inside the visible
 * strip, in both directions.
 */
[data-kt-app-sidebar-minimize="on"]:not([data-kt-app-sidebar-hoverable="true"]) .app-sidebar .menu > .menu-item > .menu-link.active > .menu-icon,
[data-kt-app-sidebar-minimize="on"][data-kt-app-sidebar-hoverable="true"] .app-sidebar:not(:hover) .menu > .menu-item > .menu-link.active > .menu-icon,
[data-kt-app-sidebar-minimize="on"]:not([data-kt-app-sidebar-hoverable="true"]) .app-sidebar .menu > .menu-item.here > .menu-link > .menu-icon,
[data-kt-app-sidebar-minimize="on"][data-kt-app-sidebar-hoverable="true"] .app-sidebar:not(:hover) .menu > .menu-item.here > .menu-link > .menu-icon {
    /* The sidebar is dark in both themes, so the glyph is white either way. */
    color: var(--bs-white);
    background-color: rgba(var(--bs-primary-rgb), 0.35);
    border-radius: var(--bs-border-radius);
    box-shadow: 0 0 0 8px rgba(var(--bs-primary-rgb), 0.35);
}

/* ----------------------------------------------------------------------
 * The import grid at full width
 * ----------------------------------------------------------------------
 * A verb sheet is nine columns. Inside the page's normal width each cell
 * comes out around 105px, which is not enough to read "understood" — the
 * browser squeezes the table to fit rather than letting it scroll, so the
 * squeezing is silent. The columns now carry a minimum width, and this is
 * the other half: a toggle that hands the grid the whole window.
 *
 * A fixed overlay rather than negative margins, because the width to escape
 * is not one number — it is the container's padding, the card's padding and
 * the sidebar, and the sidebar's is a different number depending on whether
 * it is collapsed. Covering the viewport sidesteps all three.
 * ------------------------------------------------------------------- */
[data-import-wide="on"] #import-step-review {
    position: fixed;
    inset: 0;
    z-index: 105;
    margin: 0;
    border-radius: 0;
    overflow: auto;
}

/* A duplicate row stays visible while its resolution modal is open. */
.duplicate-row-highlight > td {
    background-color: rgba(var(--bs-warning-rgb), 0.12) !important;
}

#duplicate-modal .comparison-table th,
#duplicate-modal .comparison-table td {
    vertical-align: top;
}

#duplicate-modal .dup-choice-card {
    white-space: normal;
    min-height: 100%;
}

#duplicate-modal .dup-choice-card.disabled {
    opacity: 0.55;
    pointer-events: none;
}

/*
 * Bootstrap animates a collapse by transitioning its height over 0.35s. This
 * app has no animation anywhere else, so a panel that slides open is the one
 * moving thing on the screen — and on the progress card, where the panel
 * carries several bars, the slide is a visible reflow rather than a flourish.
 * Removing the transition leaves the collapse working exactly as documented;
 * it simply arrives at once.
 */
.collapsing {
    transition: none;
}

/*
 * `hidden` has to win.
 *
 * The HTML attribute is the plainest way to say "not now", and it is what the
 * app's own scripts toggle. But Bootstrap's display utilities carry
 * `!important` — `.d-flex { display: flex !important }` — so an element that
 * is both `d-flex` and `hidden` stays on screen. That is how the activity
 * card's custom date fields showed up under every preset.
 *
 * One rule, matching what the HTML spec intends, rather than a `d-none` dance
 * at every call site.
 */
[hidden] {
    display: none !important;
}
