/* cardly-base.css — Cardly Feel design system (Phase 1).
   Load FIRST, before the face stylesheet (cardly-public/op/admin.css): face rules
   intentionally win on conflicts so untouched pages don't regress.
   Tokens + cly-* primitives only. No page layout here. */

/* ---------- Display face ---------- */
@font-face {
    font-family: 'Fraunces';
    src: url('fonts/fraunces-var.woff2') format('woff2-variations');
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
    /* type */
    --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
    --text-xs: 12px;  --text-sm: 13px;  --text-md: 15px;
    --text-lg: 18px;  --text-xl: 24px;  --text-2xl: 32px;  --text-3xl: 44px;

    /* space (4px scale) */
    --space-1: 4px;  --space-2: 8px;   --space-3: 12px;  --space-4: 16px;
    --space-5: 24px; --space-6: 32px;  --space-7: 48px;  --space-8: 64px;

    /* radius + elevation */
    --radius-sm: 6px; --radius-md: 10px; --radius-lg: 16px; --radius-full: 999px;
    --shadow-1: 0 1px 3px rgba(15, 26, 42, .10);
    --shadow-2: 0 4px 14px rgba(15, 26, 42, .12);
    --shadow-3: 0 12px 36px rgba(15, 26, 42, .18);

    /* motion */
    --dur-fast: 120ms; --dur-base: 200ms; --dur-slow: 350ms;
    --ease-out: cubic-bezier(.22, .61, .36, 1);
    --ease-spring: cubic-bezier(.34, 1.4, .64, 1);

    /* brand-derived — static navy fallbacks first, color-mix() upgrades after */
    --brand: var(--brand-primary, #1f3a5f);
    --brand-on: #ffffff;                    /* recomputed by CardlyUI.applyBrandOn() */
    --brand-tint-1: #e9eef5;
    --brand-tint-2: #d3dcea;
    --brand-hover:  #18304f;

    /* neutrals */
    --surface: #ffffff; --surface-2: #f6f7f9;
    --ink: #17202b; --ink-2: #5b6672; --line: #e3e7ec;
    --ok: #15803d; --err: #b91c1c; --warn: #b45309;
}
@supports (color: color-mix(in srgb, red 50%, white)) {
    :root {
        --brand-tint-1: color-mix(in srgb, var(--brand) 9%, white);
        --brand-tint-2: color-mix(in srgb, var(--brand) 18%, white);
        --brand-hover:  color-mix(in srgb, var(--brand) 88%, black);
    }
}

/* Dark tokens — OP face only. Two triggers, same values:
   1) explicit choice: data-theme="dark" on <html> (header toggle, localStorage cardly.theme)
   2) OS preference: prefers-color-scheme dark, unless the user explicitly chose light.
   Buyer faces stay light-first (card.jsp owns its own independent dark stage).
   In dark, panels (--surface) are LIGHTER than the page (--surface-2). */
:root[data-theme="dark"][data-face="op"] {
    --surface: #1d242e; --surface-2: #12161c;
    --ink: #e7ebf0; --ink-2: #9aa5b1; --line: #2b3441;
    --brand-tint-1: #222b37; --brand-tint-2: #2b3644;
    --shadow-1: 0 1px 3px rgba(0, 0, 0, .5);
    --shadow-2: 0 4px 14px rgba(0, 0, 0, .5);
    --shadow-3: 0 12px 36px rgba(0, 0, 0, .6);
}
@media (prefers-color-scheme: dark) {
    :root[data-face="op"]:not([data-theme="light"]) {
        --surface: #1d242e; --surface-2: #12161c;
        --ink: #e7ebf0; --ink-2: #9aa5b1; --line: #2b3441;
        --brand-tint-1: #222b37; --brand-tint-2: #2b3644;
        --shadow-1: 0 1px 3px rgba(0, 0, 0, .5);
        --shadow-2: 0 4px 14px rgba(0, 0, 0, .5);
        --shadow-3: 0 12px 36px rgba(0, 0, 0, .6);
    }
}

/* ---------- Reduced motion: kill it all ---------- */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }
}

/* ---------- Shared text helpers ----------
   .muted was defined ONLY in cardly-op.css, which the PUBLIC pages do not load, so every
   <small class="muted"> on the storefront, the thanks page and the card page rendered as
   full-weight body copy — including the under-field help text the placeholder directive
   requires to be visibly secondary. Defining it here, in the file every face loads, is what
   makes the class mean the same thing on all three. cardly-op.css keeps its identical rule
   and simply wins by load order, with the same value. */
.muted { color: var(--ink-2); }

/* Under-field help text. This is the home of the directive that forbids a `placeholder` on a
   field that already has a <label>: the example, the unit and the "leave empty to ..." rule all
   live in a <div class="form-text"> UNDER the field, where they survive the first keystroke.
   font-size is part of the rule and not optional: .muted is colour ONLY, so a bare .muted help
   line renders at full body size and reads as a second label. The three PUBLIC pages (card,
   open, corporate) still repeat this declaration inline because they shipped before this class
   existed. Those copies were NOT equivalent until 2026-08-10: they hardcoded #6b7280 against this
   rule's var(--ink-2) = #5b6672 and, sitting in a page-local <style> after the linked stylesheet at
   equal specificity, they WON on the three highest-traffic buyer pages. They now use the token, so
   deleting them is finally the no-op the earlier version of this comment wrongly claimed it already
   was. Verify the computed colour before deleting anything on the strength of a comment. */
.form-text {
    display: block;
    color: var(--ink-2);
    font-size: 12px;
    font-weight: 400;
    line-height: 1.45;
    margin-top: 4px;
}

/* ---------- Gentle, additive button feel (face CSS keeps visual ownership) ---------- */
.btn { transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out); }
.btn:active { transform: scale(.97); }
.btn.is-loading { position: relative; pointer-events: none; color: transparent !important; }
.btn.is-loading::after {
    content: ""; position: absolute; inset: 0; margin: auto;
    width: 18px; height: 18px; border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, .35); border-top-color: #fff;
    animation: cly-spin .7s linear infinite;
}
@keyframes cly-spin { to { transform: rotate(360deg); } }

/* ---------- Skeleton ---------- */
.cly-skel {
    display: block; height: 14px; border-radius: var(--radius-sm);
    background: linear-gradient(90deg, var(--surface-2) 25%, var(--line) 50%, var(--surface-2) 75%);
    background-size: 200% 100%;
    animation: cly-shimmer 1.2s ease-in-out infinite;
    margin: var(--space-2) 0;
}
@keyframes cly-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* ---------- Toasts ---------- */
.cly-toast-host {
    position: fixed; left: 50%; bottom: calc(24px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%); z-index: 10000;
    display: flex; flex-direction: column; gap: var(--space-2); align-items: center;
    pointer-events: none; width: min(92vw, 480px);
}
.cly-toast {
    pointer-events: auto; display: flex; align-items: center; gap: var(--space-3);
    background: var(--ink); color: #fff; font-family: var(--font-ui); font-size: var(--text-md);
    padding: 12px 18px; border-radius: var(--radius-md); box-shadow: var(--shadow-2);
    opacity: 0; transform: translateY(12px);
    transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-spring);
    max-width: 100%;
}
.cly-toast.show { opacity: 1; transform: translateY(0); }
.cly-toast.success { background: var(--ok); }
.cly-toast.error   { background: var(--err); }
.cly-toast-close {
    background: none; border: 0; color: inherit; font-size: 18px; line-height: 1;
    cursor: pointer; padding: 0 0 0 4px; opacity: .8;
}
.cly-toast-close:hover { opacity: 1; }

/* ---------- Modals ---------- */
.cly-modal-backdrop {
    position: fixed; inset: 0; background: rgba(10, 16, 24, .55); z-index: 10001;
    display: flex; align-items: center; justify-content: center; padding: var(--space-4);
    opacity: 0; transition: opacity var(--dur-base) var(--ease-out);
}
.cly-modal-backdrop.show { opacity: 1; }
.cly-modal {
    background: var(--surface); color: var(--ink); font-family: var(--font-ui);
    border-radius: var(--radius-lg); box-shadow: var(--shadow-3);
    width: min(92vw, 420px); padding: var(--space-5);
    transform: scale(.96); transition: transform var(--dur-base) var(--ease-spring);
}
.cly-modal-backdrop.show .cly-modal { transform: scale(1); }
.cly-modal-title { margin: 0 0 var(--space-2); font-size: var(--text-lg); font-weight: 600; }
.cly-modal-message { margin: 0 0 var(--space-4); color: var(--ink-2); font-size: var(--text-md); white-space: pre-line; }
.cly-modal-input {
    width: 100%; box-sizing: border-box; font-size: var(--text-md); font-family: var(--font-ui);
    padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-sm);
    margin-bottom: var(--space-4); background: var(--surface); color: var(--ink);
}
.cly-modal-actions { display: flex; gap: var(--space-3); justify-content: flex-end; }
/* "Scartare quanto scritto?" (cardly-ui.js, C11): the question sits left, its two buttons right. */
.cly-modal-discard-text { margin-right: auto; align-self: center; }

/* The copy-to-clipboard row inside a modal (CardlyUI.alert with opts.copyText). Was three inline
   style attributes inside an innerHTML template until 2026-09-07; that is a style-src-attr
   violation under the strict CSP, so it is a class now. */
.cly-copy-row { display: flex; gap: var(--space-2); margin-bottom: var(--space-4); }
.cly-copy-row .cly-modal-input { margin-bottom: 0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.cly-copy-row .cly-copy-btn { flex: 0 0 auto; }

/* ---------- Popover (speaker volume etc.) ---------- */
.cly-popover {
    position: absolute; z-index: 10002; background: var(--surface); color: var(--ink);
    border: 1px solid var(--line); border-radius: var(--radius-md); box-shadow: var(--shadow-2);
    padding: var(--space-4); font-family: var(--font-ui); font-size: var(--text-sm);
    min-width: 200px;
}
.cly-popover label { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); }
.cly-popover input[type="range"] { width: 100%; accent-color: var(--brand); }

/* ================================================================================================
   Utilities — the classes that replaced the inline `style="…"` attributes (CSP phase 2, 2026-09-07)
   ================================================================================================

   Why these exist at all. A strict `style-src 'self'` refuses two things and permits a third, and
   the difference decides how every one of the ~500 former inline styles had to be rewritten. Measured
   in Chrome against the Report-Only header on cardly-stage, 2026-09-07:

     - `el.style.width = '42px'`            -> NO violation. The CSSOM is not covered by style-src.
     - `el.setAttribute('style', '...')`    -> style-src-attr violation.
     - `el.innerHTML = '<b style="...">'`   -> style-src-attr violation.
     - `document.head.appendChild(style)`   -> style-src-elem violation.

   So: a STATIC style belongs in a class, here or in the page's own stylesheet; a DYNAMIC value
   (a bar width, a computed colour) is assigned through `el.style.prop` AFTER the node is in the
   document, never interpolated into markup. Do not "simplify" such an assignment back into a
   template string: it works today only because the applied policy still carries 'unsafe-inline'
   on style-src, and the whole point of this section is to be able to drop it.

   Naming: `cly-u-` (u for utility) so these never collide with the face stylesheets, which keep
   visual ownership of everything that is not pure geometry. Kept deliberately small — a page-shaped
   rule belongs in that page's own file under RESOURCES/pages/, not here. */

/* alignment — 39 sites, almost all numeric table columns */
.cly-u-right  { text-align: right; }
.cly-u-left   { text-align: left; }
.cly-u-center { text-align: center; }

/* visibility. `hidden` over `display:none` where the element is toggled: it is one attribute
   instead of one class, and it carries the meaning to assistive technology for free. This class
   stays for the cases that toggle a class rather than the attribute. */
.cly-u-hidden { display: none !important; }

/* vertical rhythm, on the 4px token scale */
.cly-u-mt-0  { margin-top: 0; }
.cly-u-mt-1  { margin-top: var(--space-1); }
.cly-u-mt-2  { margin-top: var(--space-2); }
.cly-u-mt-3  { margin-top: var(--space-3); }
.cly-u-mt-4  { margin-top: var(--space-4); }
.cly-u-mt-5  { margin-top: var(--space-5); }
.cly-u-mt-6  { margin-top: var(--space-6); }
.cly-u-mb-0  { margin-bottom: 0; }
.cly-u-mb-2  { margin-bottom: var(--space-2); }
.cly-u-mb-3  { margin-bottom: var(--space-3); }
.cly-u-mb-4  { margin-bottom: var(--space-4); }
.cly-u-m-0   { margin: 0; }

/* secondary copy — 18 sites of `color:#6b7280; font-size:12px`, which is .form-text without the
   block display. #6b7280 was a hardcoded near-miss of --ink-2 (#5b6672); the token wins here. */
.cly-u-note  { color: var(--ink-2); font-size: var(--text-xs); }
.cly-u-note-sm { color: var(--ink-2); font-size: var(--text-sm); }

/* rows of controls */
.cly-u-row      { display: flex; align-items: center; gap: var(--space-2); }
.cly-u-row-wrap { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.cly-u-actions  { display: flex; gap: var(--space-2); justify-content: flex-end; }

/* pointer affordance (directive C1) */
.cly-u-click { cursor: pointer; }

/* the generic text field that 13 sites drew by hand */
.cly-u-field {
    width: 100%; box-sizing: border-box; padding: var(--space-2);
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    font-family: var(--font-ui); font-size: var(--text-sm);
    background: var(--surface); color: var(--ink);
}

/* plain data table + its cells, the shape repeated across the operator reports */
.cly-u-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.cly-u-table th, .cly-u-table td { padding: 10px var(--space-3); border-bottom: 1px solid var(--line); }
.cly-u-table th { text-align: left; }

/* empty-state block */
.cly-u-empty { text-align: center; padding: 60px var(--space-4); color: var(--ink-3, var(--ink-2)); }

/* error / warning panel */
.cly-u-alert {
    background: #fee2e2; border-left: 4px solid #991b1b; color: #7f1d1d;
    padding: 14px var(--space-4); border-radius: var(--radius-sm);
}

/* a bar whose length is data. The length itself is set with el.style.width in JS, because a value
   that comes from data cannot be a class and must not be interpolated into markup. */
.cly-u-bar-track { background: var(--surface-2, #f3f4f6); border-radius: var(--radius-full); overflow: hidden; }
.cly-u-bar-fill  { display: block; height: 100%; background: var(--brand); }

/* Wide content (a table, a diagram) scrolls inside its own box instead of making the page scroll
   sideways. Added with the modules tab, whose history table has six columns. */
.cly-u-scroll-x
{
    overflow-x: auto;
    max-width: 100%;
}

/* ================================================================================================
   Tables that become cards on a phone (C12, S13, 2026-10-11)
   ================================================================================================

   Contract shared between the agent covering the five console tables (audit, volumi, modelli,
   esercenti, utenti) and the one covering the nine operator tables, so both sides produce the same
   shape without reading each other's files:

     - a table that must turn into cards under the phone carries class "cly-table-cards";
     - every <td> carries data-label="<that column's header, in Italian>" - set in JS when the row
       is built (td.dataset.label = ...), or written directly in the JSP for a static cell;
     - the cell holding the row's action buttons also carries class "cly-cell-actions".

   A <td> with no data-label (a colspan placeholder such as "Caricamento..." or "Nessun esercente")
   is left alone: it renders as a plain block line, same text as on a wide screen.

   Specificity note: every selector below repeats ".cly-table-cards" on purpose. The file banner at
   the top of this file says face stylesheets (cardly-admin.css, cardly-op.css, ...) load AFTER this
   one and are meant to win ties - which they would, since their own "<face>.table td"-shaped rules
   sit at the same (0,2,0)/(0,1,1) specificity as a plain ".cly-table-cards td" would. Doubling the
   class pushes this block to (0,2,1) or higher so it wins regardless of load order; without that,
   a face's unconditional padding/border-bottom/white-space on td would silently win back over this
   media query and the table would look half-carded instead of either working or visibly broken. */
@media (max-width: 600px) {
    /* The header row stays in the accessibility tree (each cell repeats its own header as
       data-label) but is not painted: there is nothing left to see once every row is its own card. */
    .cly-table-cards.cly-table-cards thead {
        position: absolute;
        width: 1px; height: 1px;
        overflow: hidden;
        white-space: nowrap;
        clip: rect(0, 0, 0, 0);
    }

    .cly-table-cards.cly-table-cards,
    .cly-table-cards.cly-table-cards tbody,
    .cly-table-cards.cly-table-cards tr {
        display: block;
        width: 100%;
    }

    .cly-table-cards.cly-table-cards tr {
        background: var(--surface);
        border: 1px solid var(--line);
        border-radius: var(--radius-md);
        padding: var(--space-3) var(--space-4);
        margin-bottom: var(--space-3);
    }
    .cly-table-cards.cly-table-cards tr:last-child { margin-bottom: 0; }

    /* Every rule in this group is scoped to td[data-label] on purpose, not to a bare td: a colspan
       placeholder (the "Caricamento...", "Nessun esercente trovato" rows, most of them marked
       ".empty" or ".muted") carries no data-label and must fall through to whatever that page's own
       class already gives it - ".empty"'s centering and generous padding among them. A bare
       ".cly-table-cards.cly-table-cards td" rule would outrank those lower-specificity classes on
       every property it declares, not only the ones this block means to change, and silently undo
       them. td:not([data-label]) only gets `display: block` below, nothing else, so it stacks full
       width without otherwise being touched. */
    .cly-table-cards.cly-table-cards td:not([data-label]) {
        display: block;
        width: 100%;
    }

    /* A labelled cell becomes a row inside the card: the label (the column header, repeated via
       attr()) on the left in the secondary colour, the value on the right. */
    .cly-table-cards.cly-table-cards td[data-label] {
        display: flex;
        justify-content: space-between;
        align-items: flex-start;
        gap: var(--space-3);
        width: 100%;
        padding: var(--space-2) 0;
        border-bottom: 1px solid var(--line);
        text-align: right;
        white-space: normal;
    }
    .cly-table-cards.cly-table-cards td[data-label]:last-child { border-bottom: 0; }
    .cly-table-cards.cly-table-cards td[data-label]::before {
        content: attr(data-label);
        flex-shrink: 0;
        color: var(--ink-2);
        font-size: var(--text-sm);
        text-align: left;
    }
    /* An empty data-label ("" - a static cell nobody bothered to label because it holds nothing
       worth repeating) would otherwise show a bare colon-less gap from the ::before box. There is
       no such cell among the five console tables today; this is a guard for whichever one shows up
       next. */
    .cly-table-cards.cly-table-cards td[data-label=""]::before { content: none; }

    /* The action cell: its label on top like every other cell, its buttons in their own full-width
       row below so each can keep a 44px touch target (C12) without crowding the value column. */
    .cly-table-cards.cly-table-cards td.cly-cell-actions {
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-2);
    }
    .cly-table-cards.cly-table-cards td.cly-cell-actions::before {
        text-align: left;
    }
    .cly-table-cards.cly-table-cards .cly-cell-actions > * {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-2);
        width: 100%;
    }
    .cly-table-cards.cly-table-cards .cly-cell-actions button,
    .cly-table-cards.cly-table-cards .cly-cell-actions a {
        min-width: 44px;
        min-height: 44px;
    }

    /* A wide TABLE earns a horizontal scroll container; a stack of cards never does, because no
       card is wider than the column it stacks in. Neutralise the two scroll containers Cardly
       already has (ADMIN's .main, and .cly-u-scroll-x on the operator history tables) exactly
       where a cly-table-cards table is what they would be scrolling. */
    .main:has(.cly-table-cards),
    .cly-u-scroll-x:has(.cly-table-cards) {
        overflow-x: visible;
    }
}
