/*
 * Styles for the SocialContent detail page (header, media gallery, payload
 * viewer). Filament only loads its own CSS bundle and does NOT scan our
 * custom Blade views, so Tailwind utility classes used there produce no CSS
 * (icons rendered at intrinsic size, gallery not gridded). We ship explicit
 * classes here instead, registered via FilamentAsset.
 *
 * COLOUR RULE (#124): a hex literal may only appear where it *defines* a custom
 * property. Everywhere else, colour comes from a token — the DS semantic roles
 * (`--tew-color-*`, which remap themselves under `.dark`) or one of the local
 * palettes declared below. A `CssTokensTest` fails the build on any stray hex.
 */

/* ------------------------------------------------------------------
   Local palettes: colour that is NOT the design system's to own.

   Both of these are Argos-specific and have no second consumer, so they are
   named here rather than pushed into the shared DS (same call we made for the
   chart palette's domain colours: the DS carries what every TEW product needs).

   1. PLATFORM colours are the *external* brands' identities (Meta's blue is
      Meta's, not ours). They are deliberately outside the DS ramp.
   2. JSON SYNTAX colours are mode-aware, and they have to be: none of the
      DS chart slots clears 4.5:1 on BOTH surfaces, because that scale is
      validated for chart *marks* (a 3:1 non-text floor). As text they would
      have failed. Each value below is measured against the surface it sits on
      (`--tew-color-bg-subtle`: #F7F9FA light, #11202A dark) and clears AA.
      Hue alone separates them, which is fine here and would not be in a chart:
      JSON is redundantly encoded — quotes mark strings, position marks keys,
      `true`/`false` are words. Colour reinforces; it never carries the meaning.
   ------------------------------------------------------------------ */
:root {
    --ssmt-platform-instagram: #e4405f;
    --ssmt-platform-facebook: #1877f2;
    --ssmt-platform-youtube: #ff0000;
    --ssmt-platform-linkedin: #0a66c2;
    --ssmt-platform-google: #4285f4;
    /* Meta (#1108). Simple Icons' own value for the brand, which is where the
       five above come from too — cross-checked by their Facebook entry still
       reading 1877F2, exactly the token on the line above.
       ⚠️ 4.96:1 light, 3.17:1 dark — clears the 3:1 non-text floor in both.
       🚨 An earlier version of this comment called it «the tightest of the
       six», which is FALSE and was published before being re-derived:
       `--ssmt-platform-linkedin` #0a66c2 is 2.92:1 on the dark surface and is
       already UNDER the floor, worse than Meta everywhere. That is a
       pre-existing defect, not one this change introduced, and it has an
       issue of its own — but the sentence written to warn people pointed at
       the wrong token and implied all six passed. */
    --ssmt-platform-meta: #0467df;

    /* TikTok (#1114). Simple Icons gives the brand `#000000`, and that is the
       reason this token did not exist: measured 2026-09-22, pure black is
       1.26:1 on the dark surface — invisible, not merely dim. So the value is
       TikTok's other brand colour, the `#25F4EE` cyan, darkened until it fits
       the window where ONE value clears the 3:1 non-text floor on both
       surfaces (relative luminance between 0.140 and 0.281).
       ⚠️ 4.59:1 light, 3.43:1 dark.

       🚨 Its absence was not an oversight, and that is why it is being filled
       rather than exempted: while `tiktok` and `tiktok_ads` drew no colour,
       «every platform has a colour rule» was a FALSE invariant, and a test
       asserting it would have been red at birth for a correct reason. The
       choice was a test with a list of exemptions — one line away from
       silencing a real omission — or removing the exemption. This is the
       second. */
    --ssmt-platform-tiktok: #0b7f7a;

    --ssmt-json-key: #7b4fc0; /* 5.34:1 */
    --ssmt-json-string: #3f7a1f; /* 4.95:1 */
    --ssmt-json-number: #0a6fa0; /* 5.24:1 */
    --ssmt-json-boolean: #9a5a12; /* 5.17:1 */
}

.dark {
    --ssmt-json-key: #c4a2f0; /* 7.73:1 */
    --ssmt-json-string: #8dc95f; /* 8.43:1 */
    --ssmt-json-number: #5fbfe6; /* 7.98:1 */
    --ssmt-json-boolean: #f0b860; /* 9.28:1 */
}

/* --- social icon (size comes from SVG width/height attrs; colour here) --- */
.ssmt-icon {
    display: inline-flex;
    line-height: 0;
    /* The containing block for the paid badge below. Harmless on every other
       icon: nothing else inside .ssmt-icon is positioned. */
    position: relative;
}

/* Most paid platforms draw their brand's glyph — linkedin_ads renders the
   LinkedIn mark — so the icon alone is ambiguous for four of the nine
   platforms (#796; it was six before #1108 gave meta_ads a mark of its own).
   The badge is the only thing that separates them at a glance, and it is
   stamped on every paid platform wherever one is drawn — tables, lists, the
   detail header (#1135) — so a platform looks the same on every page.

   ⚠️ With one exception, and it is worth naming rather than letting the
   sentence above cover it: platform_id is nullable on social_contents,
   apify_runs and apify_requests, and a row without one draws the grey globe
   with no mark, no colour and no badge — a paid platform that has lost its
   FK is indistinguishable from an unknown organic one. It is at least NAMED:
   both callers fall back to platform.unknown, because the previous fallback
   (`?? $record->platform`) was an accessor over the very relation that is
   missing, so it returned null in the one case it was written for. The
   backfill closed the FK gap in practice; nothing keeps it closed.

   ⚠️ Deliberately NOT a colour variant of the same glyph: that is the one
   candidate that fails for a colour-blind reader and washes out in dark mode,
   and it is the one the issue calls weakest. A mark with a shape and a word
   survives both.

   ⚠️ `em` here tracks the TEXT, not the icon — an earlier version of this
   comment claimed the icon and was wrong. The glyph's size is an SVG width
   attribute in pixels (`:size="20"` in the table, 24 in the detail header),
   so nothing in CSS scales with it and a caller at a much larger size would
   get this same badge. Text is the right thing to track anyway — 1.4.4 asks
   the badge to grow when the reader enlarges text — but the glyph staying
   frozen while it does is a property of the component, not of this rule.

   🚨 **This rule has a twin, and nothing links them but these two comments.**
   `.ssmt-brand__version` in `panel-marks.css` (#1129) stamps the release on the
   admin product mark and copies eight of these declarations verbatim — pill,
   ring, muted background, weight, tracking. If you restyle the badge here, go
   and do it there too; no test reads CSS, so the drift is silent. The reason
   they were not extracted, and the trigger that should extract them, are
   written at that end. */
.ssmt-icon__ads {
    position: absolute;
    right: -1.75em;
    bottom: -0.6em;
    border-radius: 0.35em;
    background: var(--tew-color-text-muted);
    color: var(--tew-color-bg);
    padding: 0 0.25em;
    font-size: 0.5em;
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: 0.02em;
    /* The glyph underneath is a solid brand colour; without a ring the badge
       reads as part of it rather than on top of it. */
    box-shadow: 0 0 0 0.12em var(--tew-color-bg);
}

/* platform-icon table cell: the column is centered (->alignCenter()), but for
   a ViewColumn Filament puts `fi-align-center` on the <td>, not on the inner
   `.fi-ta-col` flex wrapper (which stays `justify-start`), so the icon would
   sit left. Grow this span to fill the wrapper and center its own content. */
.ssmt-platform-cell {
    display: flex;
    flex: 1;
    align-items: center;
    justify-content: center;
}

/* next-refresh table cell: same ViewColumn alignment issue as the platform cell
   (the `.fi-ta-col` flex wrapper stays justify-start). Centre the date badge /
   pause icon by growing to fill the wrapper. */
.ssmt-cell-center {
    display: flex;
    flex: 1;
    align-items: center;
    justify-content: center;
}
.ssmt-cell-end {
    display: flex;
    flex: 1;
    align-items: center;
    justify-content: flex-end;
}

/* Count-column hover popover (B4b — Clienti brands/users, Utenti clients),
   rendered by lara-zeus/popover. The plugin ships no CSS and our custom Filament
   theme doesn't scan its vendor Blade, so none of the utilities in its view get
   compiled — we must supply every visual property here.

   The floating panel: `z-50` (else sibling table cells paint over it), the
   surface (`bg-white dark:bg-gray-800 ring rounded shadow`) and a content-driven
   width in place of the uncompiled `w-[…px]`. */
/* The DS semantic roles remap themselves under `.dark`, so the light/dark pair
   collapses into one rule. */
.fi-popover-content {
    z-index: 60;
    width: auto;
    min-width: 11rem;
    max-width: 20rem;
    background: var(--tew-color-surface);
    color: var(--tew-color-text);
    border: 1px solid var(--tew-color-border);
    border-radius: var(--tew-radius-md);
    box-shadow: var(--tew-shadow-md);
}

/* In-table trigger: the plugin wraps the cell in its own `grid px-3 py-4 gap-y-1`,
   which double-pads the (already padded) cell — taller row + the number indented
   out of line with the column header. Strip that padding and right-align the
   trigger so the count sits exactly like a normal ->alignEnd() numeric column. */
.fi-popover.fi-ta-text {
    padding: 0;
    row-gap: 0;
}
.fi-popover.fi-ta-text .fi-popover-trigger {
    justify-content: flex-end;
}

.ssmt-poplist {
    margin: 0;
    padding: 4px 0;
    list-style: none;
    max-height: 18rem;
    overflow-y: auto;
    text-align: left;
}
.ssmt-poplist li {
    padding: 4px 12px;
    white-space: nowrap;
}
.ssmt-poplist a {
    display: block;
    color: inherit;
    text-decoration: none;
}
.ssmt-poplist a:hover {
    text-decoration: underline;
}
.ssmt-poplist__more {
    font-size: 0.8rem;
    opacity: 0.55;
}
.ssmt-poplist__all {
    margin-top: 4px;
    padding-top: 8px;
    border-top: 1px solid var(--tew-color-border);
}
.ssmt-icon--instagram {
    color: var(--ssmt-platform-instagram);
}
.ssmt-icon--facebook {
    color: var(--ssmt-platform-facebook);
}
.ssmt-icon--youtube {
    color: var(--ssmt-platform-youtube);
}
.ssmt-icon--linkedin {
    color: var(--ssmt-platform-linkedin);
}
.ssmt-icon--google {
    color: var(--ssmt-platform-google);
}
/* Without this the Meta glyph renders in the inherited text colour, and
   `meta_ads` used to be coloured — it drew Facebook's glyph and picked up
   Facebook's rule, so #1108 would have taken a colour away. */
.ssmt-icon--meta {
    color: var(--ssmt-platform-meta);
}
/* The seventh and last slug, added by #1114 — `tiktok` and `tiktok_ads` both
   draw `si-tiktok`. Until it existed this list covered 6 of the 7 slugs
   `<x-social-icon>` can render, and nothing said so: a grey mark among
   coloured ones looks like a rendering glitch, not like a missing line.
   `PlatformSatelliteTablesTest` now presides over the list in both
   directions, which is only possible because there is no longer a platform
   that is uncoloured on purpose. */
.ssmt-icon--tiktok {
    color: var(--ssmt-platform-tiktok);
}

/* --- detail header --- */
.ssmt-content-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    width: 100%;
}
.ssmt-content-header__left {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}
.ssmt-content-header__logo {
    width: 1.5rem;
    height: 1.5rem;
    flex-shrink: 0;
    border-radius: 0.25rem;
    object-fit: contain;
}
.ssmt-content-header__brand {
    font-size: 0.875rem;
    font-weight: 400;
    color: var(--tew-color-text-subtle);
}
.ssmt-content-header__icon {
    flex-shrink: 0;
    line-height: 0;
}

/* --- media gallery --- */
.ssmt-gallery__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.5rem;
}
@media (min-width: 640px) {
    .ssmt-gallery__grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}
@media (min-width: 768px) {
    .ssmt-gallery__grid {
        grid-template-columns: repeat(5, minmax(0, 1fr));
    }
}
.ssmt-gallery__item {
    position: relative;
    display: block;
    aspect-ratio: var(--tew-media-ratio-square);
    overflow: hidden;
    border-radius: var(--tew-media-tile-radius);
    background: var(--tew-media-tile-placeholder);
    box-shadow: var(--tew-media-tile-shadow);
    transition: opacity var(--tew-dur-fast) var(--tew-ease-out);
}
.ssmt-gallery__item:hover {
    opacity: var(--tew-media-tile-hover-opacity);
}
.ssmt-gallery__item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.ssmt-gallery__overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}
.ssmt-gallery__overlay img {
    position: absolute;
    inset: 0;
    opacity: 0.6;
}
.ssmt-gallery__overlay svg {
    position: relative;
    width: 2.25rem;
    height: 2.25rem;
    color: var(--tew-color-text-on-dark);
    z-index: 1;
}
/* Media-type scrims. All three carry a white glyph, so each must clear 3:1
   against white (non-text graphic) — they do, comfortably.
   The document tile used to be RED. It is a media type, not a warning, and in
   this system red means danger: a PDF thumbnail was telling the reader
   something had gone wrong. It now uses the DS ink navy, and the glyph — not
   the colour — says which type it is.

   These three values are no longer ours: the design system ships them as
   `--tew-media-scrim-*` since v1.5.0, authored FROM this file and from
   app-social-scraper's gallery, because two apps had improvised the same
   treatment. The rule above is encoded there too, so adopting the tokens does
   not reintroduce the red (#190). */
.ssmt-gallery__overlay--video {
    background: var(--tew-media-scrim-video);
}
.ssmt-gallery__overlay--audio {
    background: var(--tew-media-scrim-audio);
}
.ssmt-gallery__overlay--document {
    background: var(--tew-media-scrim-document);
}

/* --- GLightbox overrides ---
   Filament/Tailwind's base reset (img { max-width:100%; height:auto }) fights
   GLightbox's inline px sizing on the slide image, leaving an overflow
   scrollbar. Force the image to fit the slide and clip any overflow. */
.glightbox-container .gslide-media {
    overflow: hidden;
    box-shadow: none;
}
.glightbox-container .gslide-image img {
    max-width: 100%;
    max-height: 90vh;
    width: auto !important;
    height: auto !important;
    object-fit: contain;
}
/* Videos play through Plyr (bundled with GLightbox). Plyr locks the wrapper
   to a fixed 16:9 ratio (`.plyr__video-wrapper--fixed-ratio`), which boxes
   vertical (9:16) ad creatives into a short, wide frame with empty space
   around them. Drop the fixed ratio and let the <video> flow at its own
   aspect ratio (it is normally position:absolute inside the wrapper), bounded
   to the viewport, so the player hugs the clip whatever its shape. */
.glightbox-container .gslide-video,
.glightbox-container .gslide-video .gvideo-wrapper,
.glightbox-container .gslide-video .plyr {
    width: auto !important;
    height: auto !important;
    max-width: 90vw !important;
    background: transparent !important;
    box-shadow: none !important;
}
.glightbox-container .gslide-video .plyr__video-wrapper--fixed-ratio {
    aspect-ratio: auto !important;
    padding-bottom: 0 !important;
    height: auto !important;
    width: auto !important;
    background: transparent !important;
}
.glightbox-container .gslide-video .plyr__video-wrapper video {
    position: relative !important;
    width: auto !important;
    height: auto !important;
    max-width: 90vw !important;
    max-height: 85vh !important;
    object-fit: contain;
    background: var(--tew-media-scrim-video);
}

/* --- payload viewer toolbar (expand all / collapse all / copy) ---
   One class for all three: they are the same control in the same strip and
   they change for the same reason, so a second rule for the copy button
   would be the same look written twice. */

.ssmt-payload__bar {
    display: flex;
    justify-content: flex-end;
    gap: 0.25rem;
    margin-bottom: 0.5rem;
}
.ssmt-payload__btn {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    border-radius: var(--tew-radius-md);
    background: var(--tew-color-bg-muted);
    padding: 0.25rem 0.5rem;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--tew-color-text-muted);
    cursor: pointer;
    border: 0;
}
.ssmt-payload__btn:hover {
    background: var(--tew-color-border);
}
.ssmt-payload__btn:focus-visible {
    outline: none;
    box-shadow: var(--tew-shadow-focus);
}
/* rem, not px: an icon frozen in pixels cannot grow with the text around it,
   and 1.4.4 Resize Text asks it to (accessibility §3). */
.ssmt-payload__btn-icon {
    width: 1rem;
    height: 1rem;
}
/* --- JSON CodeEditor (App\Filament\Support\JsonFieldSchema) ---
   Real CSS, not Tailwind arbitrary variants written in PHP: those compiled
   into a bundle the panel does not load, so the "expand to full screen" modal
   rendered at the same height as the field it expanded. Why, and the
   measurement, are in that class's docblock — this file ships to every admin
   page, and the explanation does not need to. */
.ssmt-json-editor .cm-editor {
    min-height: 8rem;
    max-height: 18rem;
}
.ssmt-json-editor--modal .cm-editor {
    min-height: 60vh;
    max-height: 80vh;
}

/* --- JSON tree --- */
/*
 * The line that says how much of a dataset is on screen (#852 §7).
 *
 * ⚠️ No fixed height and no px font size: `accessibility` §3 — a box frozen in
 * pixels cannot absorb text at 200%, and this one carries the sentence a
 * reader most needs to be able to enlarge.
 */
.ssmt-payload__note {
    margin-bottom: 0.5rem;
    font-size: 0.75rem;
    color: var(--tew-color-text-muted);
}
.ssmt-payload__note-source {
    margin-inline-start: 0.375rem;
    opacity: 0.85;
    font-style: italic;
}

/*
 * 🚨 The box is focusable since #852 §7 (`scrollable-region-focusable`), so it
 * needs a focus ring — a control you can tab to and cannot see is 2.4.7 traded
 * for 2.1.1. `:focus-visible` and not `:focus`, so a mouse click on the JSON
 * does not draw one.
 */
.ssmt-jt__wrap:focus-visible {
    outline: 2px solid var(--tew-color-focus, currentColor);
    outline-offset: 2px;
}
.ssmt-jt__wrap {
    max-height: 24rem;
    overflow: auto;
    border-radius: var(--tew-radius-md);
    background: var(--tew-color-bg-subtle);
    padding: 0.75rem;
    font-size: 0.75rem;
    font-family: var(--tew-font-mono);
    line-height: 1.6;
}
.ssmt-jt__node {
    border-left: 2px solid var(--tew-color-border);
    padding-left: 0.5rem;
    margin: 0;
}
.ssmt-jt__node > summary {
    list-style: none;
    cursor: pointer;
    user-select: none;
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    color: var(--tew-color-text-subtle);
}
.ssmt-jt__node > summary:focus-visible {
    outline: none;
    box-shadow: var(--tew-shadow-focus);
    border-radius: var(--tew-radius-sm);
}
.ssmt-jt__node > summary::-webkit-details-marker {
    display: none;
}
.ssmt-jt__node > summary::before {
    content: '▶';
    font-size: 0.55rem;
    color: var(--tew-color-text-subtle);
    display: inline-block;
    width: 0.8rem;
    flex-shrink: 0;
    transition: transform 0.1s ease;
}
.ssmt-jt__node[open] > summary::before {
    transform: rotate(90deg);
}
.ssmt-jt__children {
    padding-left: 1.25rem;
}
.ssmt-jt__row {
    padding: 0.05rem 0;
}
.ssmt-jt__key {
    color: var(--ssmt-json-key);
}
.ssmt-jt__str {
    color: var(--ssmt-json-string);
    word-break: break-all;
}
.ssmt-jt__num {
    color: var(--ssmt-json-number);
}
.ssmt-jt__bool {
    color: var(--ssmt-json-boolean);
}
.ssmt-jt__null {
    color: var(--tew-color-text-subtle);
    font-style: italic;
}
.ssmt-jt__empty {
    color: var(--tew-color-text-subtle);
}
.ssmt-jt__bracket {
    color: var(--tew-color-text-muted);
    font-weight: 600;
}
.ssmt-jt__count {
    font-size: 0.65rem;
    color: var(--tew-color-text-subtle);
    font-weight: normal;
    padding: 0 0.2rem;
}
.ssmt-jt__colon {
    color: var(--tew-color-text-muted);
}
.ssmt-jt__scalar {
    font-size: 0.875rem;
    color: var(--tew-color-text-muted);
}
.ssmt-jt__placeholder {
    font-size: 0.875rem;
    color: var(--tew-color-text-subtle);
}

/* No `.dark` block below this line, and that is the point: every colour above is
   a semantic DS role or a local token that already declares its own dark value,
   so dark mode needs no second copy of the stylesheet. The thirteen dark
   overrides this file used to carry were thirteen chances to drift. */

/* ------------------------------------------------------------------
   Personalisation macro badge (#757).

   LinkedIn's `%FIRSTNAME%` reaches us inside real ad copy, and printing it
   raw reads as unresolved output to an agency account. `PersonalisationMacro`
   swaps it for a badge saying the field's name; the chrome here is what makes
   it legible AS a stand-in — «nome» set in running text with no box would
   just look like a typo.

   ⚠️ COLOUR: this is a FILLED surface, so it takes a `*-solid` role and its
   declared label — the one pairing the DS guarantees clears 4.5:1 against
   itself (`tokens.json` §product layer). The obvious-looking choice was
   `info-text` on `info-bg`, and it is wrong: the `*-text` roles are measured
   against `bg`/`surface`, not against a tinted fill. Measured in the browser
   before this was written — #0A78AE on #E8F5FB is **4.38:1**, under the floor
   for text this size; #FFFFFF on #0B5E87 is **7.08:1**, and both tokens hold
   the same value in dark mode, so there is no second measurement to get wrong.

   Everything is sized in `em` — the badge rides the caption's own type
   (a11y 1.4.4/1.4.12: a box frozen in px cannot absorb text at 200%).
   ------------------------------------------------------------------ */
.ssmt-macro {
    display: inline;
    padding-inline: 0.45em;
    padding-block: 0.1em;
    border-radius: 0.35em;
    /* The EDGE, which is a separate measurement from the label. The fill is
       7.08:1 against a white card and only 1.86:1 against the dark one, so in
       dark mode the chip would melt into the surface — «evident» has to hold
       in both. `info` is the non-text role and clears the 3:1 floor on both
       surfaces (3.74:1 light, 4.73:1 dark, measured in the browser). */
    border: 1px solid var(--tew-color-info);
    background-color: var(--tew-color-primary-solid);
    color: var(--tew-color-on-primary-solid);
    font-size: 0.85em;
    font-weight: 600;
    /* The `title` explains what the badge stands for; `help` says there is
       something to hover WITHOUT promising a click, which a solid chip in the
       brand blue could otherwise imply. */
    cursor: help;
    white-space: nowrap;
}
