/* ---------------------------------------------------------------
   Elnova VV — base styles
   --------------------------------------------------------------- */

:root {
    /* Teal-blue, on white. The neutrals carry a little of the same hue —
       a pure grey beside a coloured accent reads as unconsidered rather
       than as restraint. */
    --bg: #edf1f3;
    --surface: #ffffff;
    --border: #e2e8ea;
    --border-input: #ced8dc;
    --border-hover: #a7b6bb;

    --bg-grid: rgba(13, 128, 163, .05);

    --text: #0f1a20;
    --text-secondary: #41525a;
    --text-muted: #6f838b;
    --text-faint: #96a7ad;

    /* Measured, not picked by eye. White on this is 4.53:1 — the brightest
       this blue goes while every label on it stays readable at any size.
       Anything lighter only clears the bar for large bold text, which a
       13px button label is not. */
    --accent: #0d80a3;
    --accent-hover: #0f92ba;

    /* The same hue at low opacity, for anything that needs to look selected
       without becoming a second button. */
    --accent-soft: rgba(13, 128, 163, .11);
    --accent-softer: rgba(13, 128, 163, .06);

    --good: #10714f;
    --good-soft: rgba(16, 113, 79, .11);

    --danger: #b3261e;
    --danger-border: #e6c0bc;
    --danger-bg: #fdf5f4;

    --radius: 7px;
    --radius-lg: 14px;

    /* Layered: a crisp hairline ring, a contact shadow, then a soft ambient
       one. A single large blur reads as a drop shadow, not as elevation.
       Tinted toward the accent so the shadow belongs to the same palette. */
    --shadow-card:
        0 0 0 1px rgba(15, 45, 55, .06),
        0 1px 1px rgba(15, 45, 55, .04),
        0 4px 8px -2px rgba(15, 45, 55, .05),
        0 16px 32px -8px rgba(15, 45, 55, .10);
    --shadow-pop:
        0 0 0 1px rgba(15, 45, 55, .06),
        0 8px 24px rgba(15, 45, 55, .12);
    --shadow-btn:
        inset 0 1px 0 rgba(255, 255, 255, .12),
        0 1px 2px rgba(13, 128, 163, .26);
}

*, *::before, *::after { box-sizing: border-box; }

/* The browser's own [hidden] rule is display:none at the weakest possible
   specificity, so any class that sets display — .alert is flex — beats it and
   the element shows up empty. Put it back. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;

    /* A column so the footer can be pushed to the bottom on a short page.
       Without this it sits directly under the content — on the upload page
       with one error card that left it floating in the middle of the
       screen. The modal is position:fixed and stays out of the flow. */
    min-height: 100vh;
    display: flex;
    flex-direction: column;

    font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
                 Roboto, "Helvetica Neue", Arial, sans-serif;
    font-size: 14px;
    line-height: 1.5;
    letter-spacing: -.006em;
    background: var(--bg);
    color: var(--text);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-variant-numeric: tabular-nums;
}

/* Faint graph-paper grid, faded at the edges so content sits in a pool of
   light rather than on a flat slab. Fixed and behind everything, so every
   page — auth and app alike — stands on the same ground. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    background-image:
        linear-gradient(var(--bg-grid) 1px, transparent 1px),
        linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px);
    background-size: 34px 34px;
    -webkit-mask-image: radial-gradient(ellipse 75% 65% at 50% 40%, #000 20%, transparent 100%);
            mask-image: radial-gradient(ellipse 75% 65% at 50% 40%, #000 20%, transparent 100%);
    pointer-events: none;
}

a {
    color: var(--text);
    text-decoration: none;
    border-bottom: 1px solid var(--border-input);
    transition: border-color .12s, color .12s;
}
a:hover { border-bottom-color: var(--text); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

/* --- Messages framework ---------------------------------------- */

.messages {
    position: fixed;
    top: 16px; left: 50%;
    transform: translateX(-50%);
    z-index: 20;
    margin: 0; padding: 0;
    list-style: none;
    width: min(360px, calc(100% - 32px));
}

.message {
    padding: 10px 14px;
    margin-bottom: 8px;
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-pop);
    font-size: 13px;
    color: var(--text-secondary);
}

.message--error { background: var(--danger-bg); color: var(--danger); }

/* --- Auth layout ------------------------------------------------ */

.auth {
    /* Fills what is left rather than the whole viewport: 100vh here plus a
       footer below it is one screen and a bit, so the page scrolled for no
       reason. */
    flex: 1;
    display: grid;
    place-items: center;
    padding: 48px 20px;
}

.auth__card {
    position: relative;
    width: 100%;
    max-width: 408px;
    padding: 30px 34px 34px;
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
}

/* --- Brand ------------------------------------------------------ */

.auth__brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding-bottom: 22px;
    margin-bottom: 26px;
    border-bottom: 1px solid var(--border);
}

/* Shared by the auth card and the app header — see templates/_logo.html. */
.mark {
    display: grid;
    place-items: center;
    flex: none;
    width: 32px; height: 32px;
    border-radius: 8px;
    background: var(--accent);
    color: #fff;
    box-shadow: var(--shadow-btn);
}
.mark svg { width: 18px; height: 18px; }

.auth__wordmark {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--text-secondary);
}

.auth__header { margin-bottom: 26px; }

.auth__title {
    margin: 0 0 6px;
    font-size: 21px;
    font-weight: 600;
    letter-spacing: -.024em;
}

.auth__subtitle { margin: 0; font-size: 13px; line-height: 1.45; color: var(--text-muted); }

.auth__switch {
    padding-top: 22px;
    margin: 26px 0 0;
    border-top: 1px solid var(--border);
    text-align: center;
    font-size: 13px;
    color: var(--text-muted);
}

/* --- Form fields ------------------------------------------------ */

.form { display: flex; flex-direction: column; gap: 17px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 13px; }
.field { display: flex; flex-direction: column; min-width: 0; }

.field__label {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin-bottom: 7px;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: -.004em;
    color: var(--text-secondary);
}

/* Sits against the label, not flushed to the far edge — pushed right it
   reads as a separate column rather than as part of the label. */
.field__optional {
    font-size: 12px;
    font-weight: 400;
    color: var(--text-faint);
}
.field__optional::before { content: "("; }
.field__optional::after  { content: ")"; }

.form-control {
    width: 100%;
    padding: 10px 12px;
    font: inherit;
    font-size: 14px;
    letter-spacing: -.006em;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-input);
    border-radius: var(--radius);
    box-shadow: 0 1px 1px rgba(15, 45, 55, .04);
    transition: border-color .12s ease, box-shadow .12s ease;
}

.form-control::placeholder { color: var(--text-faint); }
.form-control:hover:not(:focus) { border-color: var(--border-hover); }

.form-control:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3.5px rgba(13, 128, 163, .16);
}

/* Chrome paints autofilled inputs a flat yellow; keep the field neutral. */
.form-control:-webkit-autofill,
.form-control:-webkit-autofill:hover,
.form-control:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--text);
    -webkit-box-shadow: 0 0 0 40px var(--surface) inset;
}

.field--invalid .form-control { border-color: var(--danger); }
.field--invalid .form-control:focus { box-shadow: 0 0 0 3.5px rgba(179, 38, 30, .10); }

.field__help,
.field__error { margin-top: 7px; font-size: 12px; line-height: 1.4; }
.field__help { color: var(--text-muted); }
.field__error { color: var(--danger); }

/* --- Password reveal -------------------------------------------- */

.field__control { position: relative; display: flex; }
.field__control .form-control { padding-right: 42px; }

.field__toggle {
    position: absolute;
    top: 50%; right: 4px;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    width: 30px; height: 30px;
    padding: 0;
    background: none;
    border: none;
    border-radius: 5px;
    color: var(--text-faint);
    cursor: pointer;
    transition: color .12s, background-color .12s;
}
.field__toggle:hover { color: var(--text-secondary); background: var(--accent-softer); }
.field__toggle svg { width: 17px; height: 17px; }

/* Slash is drawn by default and hidden once the password is visible —
   the icon then shows the current state, not the pending action. */
.field__toggle[aria-pressed="true"] .field__toggle-slash { display: none; }

/* --- Alert ------------------------------------------------------ */

.alert {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    padding: 11px 13px;
    border: 1px solid var(--danger-border);
    border-radius: var(--radius);
    background: var(--danger-bg);
    color: var(--danger);
    font-size: 13px;
    line-height: 1.45;
}

.alert__icon { flex: none; width: 16px; height: 16px; margin-top: 1px; }

/* --- Buttons ---------------------------------------------------- */

.btn {
    padding: 10px 16px;
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    letter-spacing: -.006em;
    border: 1px solid transparent;
    border-radius: var(--radius);
    cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease, box-shadow .12s ease;
}

.btn--primary {
    width: 100%;
    margin-top: 8px;
    padding: 11px 16px;
    background: var(--accent);
    color: #fff;
    box-shadow: var(--shadow-btn);
}
.btn--primary:hover { background: var(--accent-hover); }
.btn--primary:active {
    background: var(--accent);
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, .28);
}

.btn--ghost {
    padding: 7px 13px;
    font-size: 13px;
    background: var(--surface);
    border-color: var(--border-input);
    color: var(--text-secondary);
    box-shadow: 0 1px 1px rgba(15, 45, 55, .04);
}
.btn--ghost:hover { border-color: var(--border-hover); color: var(--text); }

/* --- App header ------------------------------------------------- */

.header {
    background: rgba(255, 255, 255, .82);
    border-bottom: 1px solid var(--border);
    backdrop-filter: saturate(160%) blur(8px);
    -webkit-backdrop-filter: saturate(160%) blur(8px);
}

.header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    max-width: 920px;
    margin: 0 auto;
    padding: 12px 24px;
}

.header__brand {
    display: flex;
    align-items: center;
    gap: 10px;
    border-bottom: none;
}
.header__brand:hover { border-bottom: none; }

.header__wordmark {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--text-secondary);
}

/* Navigation, beside the brand. The gap after it is auto so the account
   block is pushed to the far edge without a spacer element. */
.nav {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-right: auto;
}

.nav__item {
    padding: 6px 11px;
    border-radius: var(--radius);
    font-size: 13px;
    font-weight: 500;
    color: var(--text-muted);
    white-space: nowrap;
    /* The global link rule draws a hairline under every anchor; here the
       shape is the tab, and an underline underneath it reads as a mistake. */
    border-bottom: none;
    transition: background .12s, color .12s;
}

.nav__item:hover {
    color: var(--text);
    background: var(--accent-softer);
    border-bottom: none;
}

/* Filled rather than underlined: the header already has a bottom border, and
   a second line a few pixels above it fights with it. */
.nav__item--on,
.nav__item--on:hover {
    color: var(--accent);
    background: var(--accent-soft);
}

.header__account {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-left: 14px;
    border-left: 1px solid var(--border);
}

.header__user {
    font-size: 13px;
    color: var(--text-muted);
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- App page --------------------------------------------------- */

/* Wider than it was. At 760 the tables on My work were cramped into the
   middle third of a desktop window with dead space either side. */
/* width:100% is load-bearing, not belt-and-braces. body is a column flex
   container (for the sticky footer), and an auto margin on a flex item's
   cross axis makes it take its fit-content width instead of stretching —
   which shrank this to the width of whatever card was on it, about 430px on
   the upload page. The explicit width restores the stretch; max-width still
   caps it and the auto margins still centre it. */
.page { width: 100%; max-width: 920px; margin: 0 auto; padding: 44px 24px 64px; }
.page__header { margin-bottom: 26px; }
/* A page heading, not a card heading. 21px read as the latter and left the
   top of every page without a clear first line. */
.page__title {
    margin: 0 0 7px;
    font-size: 26px;
    font-weight: 600;
    letter-spacing: -.028em;
    line-height: 1.2;
}
.page__lede { margin: 0; font-size: 14px; color: var(--text-muted); }

/* Same surface treatment as the auth card, so the two read as one product. */
.card {
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

.card__title {
    margin: 0;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: -.004em;
    color: var(--text-secondary);
}

.detail {
    display: grid;
    grid-template-columns: 170px 1fr;
    margin: 0;
}

.detail dt,
.detail dd {
    margin: 0;
    padding: 12px 20px;
    border-top: 1px solid var(--border);
    font-size: 13px;
}

.detail dt { color: var(--text-muted); }
.detail dd { color: var(--text); }
.detail dt:first-of-type, .detail dd:first-of-type { border-top: none; }

/* --- Upload ----------------------------------------------------- */

.upload { margin-bottom: 32px; }

.dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    padding: 36px 24px;
    margin: 14px;
    border: 1.5px dashed var(--border-input);
    border-radius: 10px;
    background: #fbfbfc;
    text-align: center;
    cursor: pointer;
    transition: border-color .12s, background-color .12s;
}
.dropzone:hover,
.dropzone.is-dragging { border-color: var(--accent); background: #f6f7f8; }
.dropzone:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3.5px rgba(13, 128, 163, .15); }

.dropzone__icon { color: var(--text-faint); }
.dropzone__icon svg { display: block; width: 26px; height: 26px; }

.dropzone__title { font-size: 14px; font-weight: 500; color: var(--text-secondary); }
.dropzone__link { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.dropzone__hint { font-size: 12px; color: var(--text-faint); }

/* Visually hidden, but still focusable and clickable through the label. */
.dropzone__input {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.upload__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 13px 20px;
    border-top: 1px solid var(--border);
}

.upload__file {
    font-size: 13px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.upload__file.is-set { color: var(--text); }

.btn--inline { width: auto; margin: 0; flex: none; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn:disabled:hover { background: var(--accent); }

/* Working — the button keeps full contrast, it is busy rather than unavailable. */
.btn.is-busy { opacity: 1; cursor: progress; }
.btn.is-busy:hover { background: var(--accent); }

.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; }

.spinner {
    flex: none;
    width: 13px; height: 13px;
    border: 2px solid rgba(255, 255, 255, .35);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin .65s linear infinite;
}

/* The same spinner on a card rather than on a button. White on white is
   nothing at all, so it takes the heading's own colour. */
.spinner--dark {
    display: inline-block;
    vertical-align: -1px;
    margin-right: 7px;
    border-color: rgba(0, 0, 0, .18);
    border-top-color: currentColor;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* --- Progress ---------------------------------------------------- */

.progress {
    height: 3px;
    margin: 0 14px;
    border-radius: 2px;
    background: var(--border);
    overflow: hidden;
}

.progress__bar {
    width: 0;
    height: 100%;
    border-radius: 2px;
    background: var(--accent);
    transition: width .2s ease-out;
}

/* Upload is measurable; the analysis that follows is not, so the bar stops
   reporting a number and just shows that work is still happening. */
.progress--working .progress__bar {
    width: 35%;
    transition: none;
    animation: sweep 1.3s ease-in-out infinite;
}

@keyframes sweep {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(320%); }
}

/* --- Clip results ----------------------------------------------- */

.results__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}

.results__title { margin: 0; font-size: 15px; font-weight: 600; letter-spacing: -.014em; }
.results__meta { font-size: 12px; color: var(--text-faint); }

/* Handing the clips in. Sits under the two clip lists because that is the
   order the decision is made in: look at the clips, then send them. */
.results__send {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}

.results__hint {
    margin: 0;
    font-size: 12px;
    color: var(--text-faint);
}

/* Sent is a finished state, not a disabled one: the button keeps its weight
   so the row still reads as done rather than as something that failed. */
.btn.is-done,
.btn.is-done:hover {
    background: var(--good);
    border-color: transparent;
    color: #fff;
    opacity: 1;
    cursor: default;
}

/* The expression read off the usable footage. Sits next to the title, and
   pushes the timing meta to the far side of the head row. */
.emotion {
    margin-right: auto;
    padding: 2px 9px;
    border-radius: 20px;
    background: var(--accent-softer);
    font-size: 11px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: capitalize;
    white-space: nowrap;
    cursor: default;
}

.emotion--happy     { background: rgba(26, 127, 75, .12);  color: var(--good); }
.emotion--sad       { background: rgba(47, 106, 196, .12); color: #2f6ac4; }
.emotion--angry     { background: rgba(190, 62, 48, .12);  color: #be3e30; }
.emotion--neutral   { background: rgba(65, 82, 90, .10);   color: var(--text-secondary); }

.clips { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }

.clipset__head { display: flex; align-items: center; gap: 8px; margin-bottom: 9px; }
.clipset__title { margin: 0; font-size: 13px; font-weight: 600; color: var(--text-secondary); }

.dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.dot--good { background: var(--good); }
.dot--bad  { background: var(--danger); }

.badge {
    margin-left: auto;
    padding: 1px 7px;
    border-radius: 20px;
    background: var(--accent-softer);
    font-size: 11px;
    font-weight: 600;
    color: var(--text-muted);
}

/* Plain block, no display switching. This used to be a grid that flipped to
   block via :has(.clip); one less thing that can silently not apply. */
.clipset__body { min-height: 96px; }

.empty {
    margin: 0;
    padding: 30px 20px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-faint);
    text-align: center;
}

/* Compact rows; clicking one opens the cut clip in the modal. */
.clipset__body { min-height: 96px; }


.modal {
    position: fixed;
    inset: 0;
    z-index: 40;
    display: grid;
    place-items: center;
    padding: 24px;
}

.modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(16, 18, 22, .55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

.modal__box {
    position: relative;
    width: min(760px, 100%);
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-pop);
    overflow: hidden;
}

.modal__video {
    display: block;
    width: 100%;
    max-height: 70vh;
    background: #0d0f12;
}

.modal__why:not(:empty) {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px 14px 0;
}

.modal__fault { display: flex; align-items: baseline; gap: 8px; }
.modal__detail { font-size: 12px; color: var(--text-muted); }

.modal__bar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 14px;
    border-top: 1px solid var(--border);
}

.modal__label { font-size: 13px; color: var(--text-secondary); }

.modal__download {
    margin-left: auto;
    border-bottom: none;
    font-size: 13px;
    color: var(--text-muted);
}
.modal__download:hover { color: var(--text); border-bottom: none; }

/* --- Small screens ---------------------------------------------- */

@media (max-width: 560px) {
    .auth { padding: 28px 16px; }
    .auth__card { padding: 26px 22px 28px; }
    .field-row { grid-template-columns: 1fr; gap: 17px; }

    .header__inner { padding: 11px 16px; gap: 10px; }
    .header__user { display: none; }   /* the email would crowd out the button */

    /* Nothing left in the account block but the button, so the rule beside
       it has nothing to separate. */
    .header__account { padding-left: 0; border-left: none; }

    /* The wordmark goes; the mark alone is enough to say where you are, and
       the two tabs need the room more. */
    .header__wordmark { display: none; }
    .nav__item { padding: 6px 9px; }

    .page { padding: 28px 16px 40px; }
    .detail { grid-template-columns: 1fr; }
    .detail dd { padding-top: 0; border-top: none; }

    .clips { grid-template-columns: 1fr; gap: 20px; }
    .dropzone { padding: 28px 18px; margin: 12px; }
    .upload__footer { flex-direction: column; align-items: stretch; }
    .btn--inline { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    * { transition-duration: .01ms !important; animation-duration: .01ms !important; }

    /* Killing every animation would leave the wait with no feedback at all,
       so the busy indicators become static instead of disappearing. */
    .spinner { animation: none; border-top-color: rgba(255, 255, 255, .35); }
    .progress--working .progress__bar { animation: none; width: 100%; opacity: .5; }
}

/* --- My work ------------------------------------------------------ */

/* The figure the page is opened to see, and its supporting numbers beside
   it. Four equal tiles gave them all equal weight and made the row read as
   a dashboard nobody asked for. */
.summary {
    display: grid;
    grid-template-columns: minmax(220px, 1fr) minmax(240px, 1.15fr);
    gap: 14px;
    margin-bottom: 22px;
}

.summary__main {
    display: flex;
    flex-direction: column;
    /* Centred: the side card sets the row height, and left at the top this
       one ended with a band of empty white under the note. */
    justify-content: center;
    padding: 22px 24px;
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
}

.summary__label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-muted);
}

.summary__figure {
    margin: 4px 0 6px;
    font-size: 32px;
    font-weight: 600;
    letter-spacing: -.03em;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.summary__note { font-size: 12px; color: var(--text-faint); }

.summary__side {
    display: grid;
    align-content: center;
    gap: 2px;
    margin: 0;
    padding: 14px 20px;
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
}

.summary__item {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 7px 0;
    border-bottom: 1px solid var(--border);
}
.summary__item:last-child { border-bottom: none; }

.summary__item dt { font-size: 13px; color: var(--text-muted); }
.summary__item dd {
    margin: 0;
    font-size: 14px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* --- Tabs -------------------------------------------------------- */

.tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 14px;
    border-bottom: 1px solid var(--border);
}

.tab {
    padding: 9px 14px;
    font-size: 13px;
    font-weight: 500;
    color: var(--text-muted);
    border-bottom: 2px solid transparent;
    /* The global link rule draws a hairline under every anchor; here the
       underline is the selected state and must not be on by default. */
    margin-bottom: -1px;
}
.tab:hover { color: var(--text); border-bottom-color: var(--border-hover); }

.tab--on,
.tab--on:hover {
    color: var(--text);
    border-bottom-color: var(--accent);
}

/* --- Tables ------------------------------------------------------ */

/* Wide tables scroll inside the card; the page itself never does. */
.panel { padding: 0; overflow-x: auto; }

.wtable { width: 100%; border-collapse: collapse; font-size: 14px; }

.wtable th {
    text-align: left;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-faint);
    padding: 11px 16px;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}

.wtable td {
    padding: 13px 16px;
    border-bottom: 1px solid var(--border);
    color: var(--text-secondary);
    vertical-align: middle;
}

.wtable tbody tr:last-child td { border-bottom: none; }
.wtable tbody tr:hover td { background: var(--accent-softer); }

.wtable__num,
.wtable th.wtable__num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Last column: right-aligned content, but the pill reads better flush right
   than centred under a right-aligned heading. */
.wtable__end,
.wtable th.wtable__end { text-align: right; white-space: nowrap; }

.wtable__name {
    color: var(--text);
    font-weight: 500;
    /* Camera file names are long enough to set the column width on their
       own; clipped, the rest of the row stays readable. */
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wtable__when { white-space: nowrap; color: var(--text-muted); }
.wtable__dim { color: var(--text-faint); font-size: 12px; font-weight: 400; }

/* What a payment was made of, one emotion per row, under the payment itself.
   Quieter than the total and hairlined between so the breakdown reads as part
   of the row above rather than as more payments. */
.wtable__sub td {
    padding-top: 7px;
    padding-bottom: 7px;
    font-size: 12px;
    color: var(--text-muted);
    border-bottom: 1px dotted var(--border);
}

.wtable__sub .wtable__name {
    font-weight: 400;
    color: var(--text-muted);
    padding-left: 28px;
}

.wtable__sub:hover td { background: transparent; }

/* The last emotion of a payment closes the group off properly. */
.wtable__sub + tr:not(.wtable__sub) td { border-top: 1px solid var(--border); }

.pill {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: 500;
    white-space: nowrap;
}

.pill--paid { background: var(--good-soft); color: var(--good); }
.pill--pending { background: var(--accent-softer); color: var(--text-muted); }

/* A take that will never be paid for, either because it was not accepted or
   because none of it was usable. Read as a dead end, not as a warning of
   something still to come. */
.pill--no { background: var(--danger-bg); color: var(--danger); }

/* --- Pager ------------------------------------------------------- */

.pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 14px;
    font-size: 13px;
}

.pager__step {
    padding: 6px 13px;
    border: 1px solid var(--border-input);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text-secondary);
    font-weight: 500;
}
.pager__step:hover { border-color: var(--border-hover); color: var(--text); }

.pager__step--off {
    color: var(--text-faint);
    background: transparent;
    border-style: dashed;
    cursor: default;
}

.pager__at { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.pager__count { color: var(--text-faint); }

/* --- Empty state ------------------------------------------------- */

.empty { padding: 40px 24px; text-align: center; }
.empty__text { margin: 0 0 6px; font-size: 15px; font-weight: 500; }
.empty__note { margin: 0 0 16px; font-size: 13px; color: var(--text-muted); }
.empty .btn { margin-top: 8px; }

@media (max-width: 640px) {
    .summary { grid-template-columns: 1fr; }
    .summary__figure { font-size: 28px; }
}

/* --- What the check looks for ------------------------------------ */

/* Sits under the upload box until there are results to read instead. Not a
   card: it is reference rather than a thing to act on, and giving it the
   same surface as the upload box would put the two on equal footing. */
.guide {
    margin-top: 34px;
    padding-top: 26px;
    border-top: 1px solid var(--border);
}

.guide__title {
    margin: 0 0 18px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.guide__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 22px 30px;
}

.guide__item h3 {
    margin: 0 0 5px;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: -.008em;
    color: var(--text);
}

/* A short rule in the accent, in place of the icon this would otherwise
   want. Icons here would be decoration; six of them would be clutter. */
.guide__item h3::before {
    content: "";
    display: block;
    width: 18px;
    height: 2px;
    margin-bottom: 9px;
    border-radius: 2px;
    background: var(--accent);
}

.guide__item p {
    margin: 0;
    font-size: 13px;
    line-height: 1.55;
    color: var(--text-muted);
}

.guide__foot {
    margin: 24px 0 0;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    font-size: 12px;
    color: var(--text-faint);
}

/* Emotion picker, in the upload footer beside the file name.

   Named apart from .field/.field__label/.field__control on purpose. Those are
   the stacked form fields used by login and signup: .field is
   flex-direction:column, which is what put this label above its select, and
   reusing .field__label here quietly overrode the margin every form label on
   the site depends on. */
.picker {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-left: auto;
    margin-right: 14px;
}

.picker__label {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-secondary);
    white-space: nowrap;
}

/* Holds the select and the padlock that replaces its arrow once locked. */
.picker__control { position: relative; display: flex; }

/* A select sized for a row of controls rather than a stacked form.

   The native arrow is replaced with one drawn here, because the platform
   default does not follow the border colour and reads as a different control
   next to the text inputs. */
.form-control--inline {
    width: auto;
    min-width: 148px;
    padding: 8px 32px 8px 11px;
    font-size: 13px;
    cursor: pointer;
    appearance: none;
    background-image: url("data:image/svg+xml;charset=utf-8,\
%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E\
%3Cpath d='M3 4.75 6 7.75l3-3' fill='none' stroke='%23767c86' \
stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 12px;
}

/* Nothing chosen yet: lighter than a real value, so "Choose…" does not read
   as an answer.

   --text-muted rather than --text-faint: faint measures 2.49:1 on white,
   which is unreadable, and this is a prompt to act on rather than decoration.
   Muted is 3.97:1 and still plainly lighter than a chosen value at 17.66:1,
   so the distinction survives without the text going illegible. */
.form-control--inline:invalid { color: var(--text-muted); }

/* The popup list inherits its colour from the select, so while the
   placeholder is showing every option in the open dropdown was rendering in
   that same washed-out grey. Set them back explicitly — only the placeholder
   row stays light. */
.form-control--inline option { color: var(--text); }
.form-control--inline option[value=""] { color: var(--text-muted); }

.form-control--inline:focus-visible {
    outline: none;
    border-color: var(--border-hover);
    box-shadow: 0 0 0 3px rgba(20, 22, 26, .07);
}

/* Locked once the take has been analysed — the emotion is what the clips were
   judged against, so it cannot be changed underneath them. Unclickable, with
   the arrow swapped for a padlock.

   Kept at --text-secondary, not the --text-muted a disabled control would
   usually get: this still has to be READ, because it is the label the take
   was filed and will be paid under. Muted measures 3.49:1 against this
   background, under the 4.5:1 that 13px text needs; secondary is 7.16:1.
   Being locked is carried by the padlock and the flat background instead. */
.form-control--inline:disabled {
    cursor: default;
    color: var(--text-secondary);
    background-color: var(--bg);
    background-image: none;
    border-color: var(--border);
    box-shadow: none;
}

.picker__lock {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    color: var(--text-faint);
    pointer-events: none;
}

@media (max-width: 640px) {
    .picker { margin: 0; width: 100%; }
    .picker__control { flex: 1; }
    .form-control--inline { width: 100%; }
}

/* ---------------------------------------------------------------
   Emotion check — what this project adds to the Elnova VV sheet
   --------------------------------------------------------------- */

/* Emotion picker, in the upload footer beside the file name. */
.upload__emotion {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-left: auto;
    margin-right: 14px;
}

.upload__emotion-label {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-secondary);
    white-space: nowrap;
}

/* A select sized for a row of controls rather than a stacked form. */
.form-control--inline {
    width: auto;
    min-width: 130px;
    padding: 8px 11px;
    font-size: 13px;
}

@media (max-width: 640px) {
    .upload__emotion { margin: 0 0 12px; width: 100%; }
    .form-control--inline { flex: 1; }
}

/* .card carries no padding or margin of its own — in Elnova VV every one of
   them sits in a grid that supplies both. These pages stack them directly,
   so they have to supply it here. */
.page > .card { margin-bottom: 18px; }

/* The video is the card's only content, so it is inset by hand. */
.page > .card > .player {
    width: calc(100% - 40px);
    margin: 0 20px 20px;
}

/* Capped rather than free: a portrait take at full width pushes everything
   below it off the screen. */
.player {
    display: block;
    max-height: 420px;
    background: #000;
    border-radius: var(--radius);
}

.back {
    font-size: 13px;
    color: var(--accent);
    border-bottom-color: transparent;
}
.back:hover { border-bottom-color: var(--accent); }

/* The back link sits above the title, so it needs its own line. */
.page__header .back { display: inline-block; margin-bottom: 10px; }

/* Separator between the emotion chip and the date in the page lede. */
.page__dot { margin: 0 7px; color: var(--text-faint); }

/* Placeholder in the clip columns until the overnight run has been through.
   Centred: there is no list for it to head, and flush left it reads as the
   first row of one. */
.soon {
    display: grid;
    place-items: center;
    min-height: 96px;
    margin: 0;
    padding: 20px;
    font-size: 13px;
    color: var(--text-faint);
    text-align: center;
}

/* --- The verdict, on the upload page ---------------------------- */

.verdict-card { margin-top: 18px; }

/* Colour carries the answer before the words are read, so the three states
   are as far apart as the palette allows. */
.verdict {
    padding: 16px 20px;
    border-bottom: 1px solid var(--border);
}

/* The margin belongs under the heading only when a line follows it — on a
   refusal the heading is the whole banner. */
.verdict__title:not(:last-child) { margin-bottom: 4px; }

.verdict__title {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -.015em;
}

/* Which emotion the refusal was against. Inside the heading rather than
   under it: it is part of the sentence, not a second line of detail. */
.verdict__tried { font-size: 13px; font-weight: 400; opacity: .8; }
.verdict__tried::before { content: "— "; }

.verdict__text { margin: 0; font-size: 13px; line-height: 1.5; }

.verdict--ok      { background: var(--good-soft);     color: var(--good); }
.verdict--no      { background: var(--danger-bg);     color: var(--danger); }
.verdict--unknown { background: var(--accent-softer); color: var(--text-secondary); }

/* On a refusal the banner is the whole card, and the rule under it would be
   a line with nothing beneath it. */
.verdict:last-child { border-bottom: 0; }

/* The one action the card offers, and only when the take passed. */
.verdict__actions { padding: 18px 20px; }
.verdict__actions form { margin: 0; }

.clip {
    display: flex;
    align-items: baseline;
    gap: 10px;
    width: 100%;
    padding: 11px 15px;
    border: none;
    border-top: 1px solid var(--border);
    background: none;
    font: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
    transition: background-color .12s;
}
.clip:first-child { border-top: none; }
.clip:hover { background: var(--accent-softer); }
.clip--nofile { cursor: default; color: var(--text-faint); }
.clip--nofile:hover { background: none; }

.clip__play {
    flex: none;
    width: 14px; height: 14px;
    align-self: center;
    color: var(--text-faint);
}
.clip:hover .clip__play { color: var(--text); }
.clip--nofile .clip__play { opacity: .4; }

.clip__time { font-variant-numeric: tabular-nums; color: var(--text); }
.clip__length { font-size: 12px; color: var(--text-faint); }

.clip__reasons {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 4px;
    margin-left: auto;
}

.clip__reason {
    padding: 1px 7px;
    border-radius: 20px;
    background: var(--danger-bg);
    font-size: 11px;
    color: var(--danger);
    white-space: nowrap;
}

.empty {
    margin: 0;
    padding: 30px 20px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-faint);
    text-align: center;
}

/* --- Clip modal --------------------------------------------------- */

/* --- Footer ------------------------------------------------------ */

.footer {
    /* Takes up the slack, which is what puts it at the bottom of a short
       page and directly under the content on a long one. */
    margin-top: auto;
    padding: 22px 20px 30px;
    border-top: 1px solid var(--border);
}

.footer__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    max-width: 920px;
    margin: 0 auto;
    font-size: 12px;
}

.footer__mark {
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-faint);
}

.footer__links { display: flex; gap: 18px; }

.footer__links a {
    color: var(--text-muted);
    border-bottom-color: transparent;
}
.footer__links a:hover { color: var(--text); border-bottom-color: var(--border-input); }

/* --- Legal pages -------------------------------------------------- */

.legal { padding: 26px 30px 30px; }

.legal__lede {
    margin: 0 0 26px;
    padding-bottom: 20px;
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border);
}

.legal h2 {
    margin: 30px 0 10px;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: -.01em;
}
.legal h2:first-of-type { margin-top: 0; }

.legal p, .legal li {
    margin: 0 0 12px;
    font-size: 13px;
    line-height: 1.65;
    color: var(--text-secondary);
}

.legal ul { margin: 0 0 12px; padding-left: 20px; }
.legal li { margin-bottom: 5px; }

.legal .wtable { margin: 0 0 14px; }
.legal .wtable th { width: 190px; vertical-align: top; }

/* Something a lawyer has to settle before this page is binding. Marked
   rather than left to read like settled text — an unreviewed clause that
   looks finished is worse than an obvious gap. */
.legal__flag {
    padding: 12px 14px;
    margin: 0 0 14px;
    background: var(--danger-bg);
    border-left: 3px solid var(--danger-border);
    border-radius: 0 var(--radius) var(--radius) 0;
    color: var(--danger);
}

.legal__note {
    margin: 30px 0 0;
    padding: 16px 18px;
    background: var(--accent-softer);
    border-radius: var(--radius);
    font-size: 13px;
    line-height: 1.6;
    color: var(--text-secondary);
}

/* The emotion menu once the upload is under way. Not `disabled`, because a
   disabled select is left out of the POST and the answer would never arrive;
   this only takes away the means to change it. */
.form-control.is-locked {
    pointer-events: none;
    background: var(--accent-softer);
    color: var(--text-muted);
    border-style: dashed;
}

.dropzone.is-locked { pointer-events: none; opacity: .55; }
