/* Unistone Colour Themes — base layer + controls.
 *
 * Load order is theme-tokens.css (generated) then this file then theme-overrides.css.
 *
 * THE INVARIANT: this plugin sets colour, never geometry. No width, height, margin,
 * padding, position, display, font-size or line-height is set on any element this
 * plugin does not itself own (`.ust-theme*`). On 2026-07-29 an ID selector of ours
 * outranked Elementor's per-image sizing and reverted every sized image on the site;
 * axe could not see it and the client found it. Enforced by
 * `python3 audit-tooling/theme/assert-colour-only.py`.
 *
 * SPECIFICITY POLICY, and it is deliberate in both directions:
 *   - The BASE layer below uses :where(), which has ZERO specificity. Anything the
 *     site's own stylesheets author beats it. That is correct: the base is a floor for
 *     elements nobody styled, and it must never win a fight it was not measured to win.
 *   - The OVERRIDE layer (theme-overrides.css) uses real specificity and !important,
 *     but ONLY for selectors a measurement proved were resisting. Each rule there
 *     carries the count that justifies it.
 */

/* ---------------------------------------------------------------- base layer */
/* Applies only when a theme is active. Normal = no attribute = site untouched, byte
   for byte the rendering the conformance report describes. */

:root[data-ust-theme] :where(html, body) {
  background-color: var(--ust-bg);
  color: var(--ust-fg);
}

/* Only the neutral PAGE WRAPPERS are made transparent, so the palette's background
 * reaches through them.
 *
 * `header`, `footer`, `nav`, `section` and the Elementor container classes were in this
 * list and had to come out. They carry the site's deliberately-dark bands — the navy
 * nav, the hero — and forcing them transparent dropped their white text onto a yellow
 * page: 264 nav links at 1.03:1. :where() gives this zero specificity, so an authored
 * background still wins, but these elements often have no authored rule of their own and
 * simply inherit the band from a parent. Zero specificity is not zero consequence. */
:root[data-ust-theme] :where(#page, #content, #ust-main, .site, .ast-container, .site-content) {
  background-color: transparent;
  color: inherit;
}

/* Text elements that should follow the theme when they have no colour of their own.
 *
 * `span` and `div` were in this list and had to come out. They are generic containers, and
 * on this site they routinely DO carry their own colour — the footer's "Follow Us" label is
 * a `span.elementor-icon-list-text` with `color: var(--e-global-color-secondary)`, which
 * renders white on the dark band. This rule outranked it and handed the span its anchor's
 * link colour instead: 1.6:1 on the Yellow palette, against 18.8:1 with the theme off.
 *
 * Note that `:where()` has zero specificity, so on paper it loses to the span's own rule —
 * but it does not lose to it here, because the span's rule and this one both apply and this
 * one comes later in the cascade. Zero specificity is not zero consequence; that is the
 * second time in this build the same assumption has been wrong.
 *
 * It also cannot be fixed by ADDING a rule. `revert` and `unset` both resolve to `inherit`
 * for an inherited property like `color`, so every candidate override reproduced the defect
 * exactly. The only fix for a rule that should not exist is deleting it. */
:root[data-ust-theme] :where(
  p, li, td, th, dd, dt, figcaption, label, blockquote, cite,
  h1, h2, h3, h4, h5, h6, strong, em, small
) {
  color: inherit;
}

:root[data-ust-theme] :where(a) { color: var(--ust-link); }
:root[data-ust-theme] :where(a:hover, a:focus) { color: var(--ust-link-hover); }
:root[data-ust-theme] :where(a:visited) { color: var(--ust-visited); }

:root[data-ust-theme] :where(hr, table, th, td, fieldset, .elementor-divider-separator) {
  border-color: var(--ust-border);
}

:root[data-ust-theme] :where(input, select, textarea) {
  background-color: var(--ust-bg-raise);
  color: var(--ust-fg);
  border-color: var(--ust-border);
}
:root[data-ust-theme] :where(input, textarea)::placeholder { color: var(--ust-muted); }

/* NOT :where(::selection) — a pseudo-ELEMENT is invalid inside :where(), so the entire rule
   was discarded by the parser and selection colours were never themed at all. Confirmed in the
   CSSOM: no rule containing ::selection survived. The same "parsed and did nothing" class as
   the 100 rules that referenced undefined tokens. */
:root[data-ust-theme] ::selection {
  background-color: var(--ust-accent);
  color: var(--ust-on-accent);
}

/* Focus visibility must survive every palette (2.4.7). --ust-focus is proven >=3:1
   against both bg and bg-alt in all four palettes. */
:root[data-ust-theme] :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  /* TWO-TONE RING. --ust-focus is proven against bg and bg-alt only, and the light palettes
     deliberately keep the site's #0f1021 dark bands — so a near-black outline landed on a
     near-black band and disappeared: yellow 1.12:1, blue 1.07:1, orange 1.03:1 on the footer,
     measured. A keyboard user had no focus indicator there at all (2.4.7, 1.4.11), and it was
     introduced by this plugin.
     The box-shadow adds a second concentric ring in --ust-focus-alt, the token already proven
     against the opposite surface. Whatever the ring lands on, one of its two tones contrasts.
     Both properties are colour-only, so the colour-only invariant is intact. */
  box-shadow: 0 0 0 6px var(--ust-focus-alt);
  outline: 3px solid var(--ust-focus);
  outline-offset: 2px;
}

/* ------------------------------------------------- images and client logos */
/* Marks are NEVER recoloured, inverted or filtered. Many of the ~48 client logos are
   third-party registered trademarks whose brand guidelines forbid altering mark colours, so
   the theme puts a neutral plate BEHIND the artwork and never touches the artwork itself.

   THE PLATE RULE IS NOT HERE. It is generated into theme-overrides.css from
   logo-ink-census.json, as an allowlist of the 22 image families whose ink was MEASURED to be
   invisible on #000 and legible on the plate.

   Two hand-written rules stood here and did nothing, and both are deleted rather than left as
   apparent coverage:
     .ust-plate img, [data-ust-plate] img  — neither the class nor the attribute is applied
       anywhere in this project. The same defect as the retired `.ust-logo-wall` selector,
       reintroduced in the file that survived it.
     svg[fill="currentColor"] { fill: currentColor }  — a no-op by construction. */

/* ------------------------------------------------------------- the controls */
/* This is the only element whose geometry this plugin owns. */

/* A FIXED DARK UTILITY BAR, in every palette.
 *
 * It does not follow the theme, and that is deliberate. This is chrome, not content — SEBI's
 * own utility row stays one colour while the page beneath it changes. Keeping it fixed means
 * its contrast is proven once (white on #0b0620 is ~18:1) instead of five times, and it reads
 * as part of the header block rather than as a light strip stacked on top, which is what Sid
 * flagged on 2026-08-14.
 *
 * It does NOT try to colour-match the header beneath it. Measured: the header paints no
 * background of its own — the dark band is the hero showing through — and every page's hero
 * differs, from rgb(11,2,36) on /about-us/ to rgb(60,52,81) on /disclaimer/. There is no single
 * colour or gradient to match, so it stops pretending and becomes a deliberate bar instead. */
.ust-theme {
  background-color: #0b0620;
  color: #ffffff;
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
  font-size: 13px;
  line-height: 1.4;
}
.ust-theme a { color: #ffffff; }

/* Visually-hidden legend for the text-size group. Never display:none — the group needs its
   accessible name. */
.ust-theme__srlegend {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The site already HAS a skip link, clipped to 1px until focused. SEBI shows theirs
   permanently, and it is the most useful thing in their bar, so this one is always visible.
   Astra's hidden one still exists and still works; two links to the same target is mild
   redundancy in the tab order, not a defect. */
.ust-theme__skip {
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 255, 255, 0.35);
  padding: 2px 0;
  white-space: nowrap;
}
.ust-theme__skip:hover { border-bottom-color: #ffd166; }

.ust-theme__fs { display: flex; align-items: center; gap: 4px; }
/* Kept level with the swatches (28px). At their old 30px they set the row height instead, so
   shrinking the squares alone would have moved the squares and left the band the same size. */
.ust-theme__fsbtn {
  flex: 0 0 auto;
  width: 32px;
  height: 28px;
  padding: 0;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 0;
  color: #ffffff;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.ust-theme__fsbtn:hover { border-color: #ffd166; }
/* `.ust-theme .ust-theme__fsbtn` — (0,2,0) loses to the site-wide focus rule above at (0,3,0),
   so in yellow, blue and orange the computed outline on these buttons was the palette's
   near-black focus token against the fixed dark bar: 1.06 / 1.13 / 1.08:1. Not a 2.4.7 failure,
   because the white box-shadow ring rescued it — but by accident, from a rule added for a
   different surface. Its sibling `.ust-theme .ust-theme__btn` already carried this fix; this
   one had been left behind. */
.ust-theme .ust-theme__fsbtn:focus-visible { outline: 3px solid #ffd166; outline-offset: 2px; }

/* aria-disabled had NO styling at all, so at the limit a sighted visitor saw an unchanged
   button that simply ignored them. */
.ust-theme .ust-theme__fsbtn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: default;
}

.ust-theme__colours { display: flex; align-items: center; gap: 10px; }
.ust-theme[hidden] { display: none; }

/* RIGHT-ALIGNED, matching sebi.gov.in — measured from their live header 2026-08-14, not
   recalled. Their five swatches are 29-31 x 25px hard-edged squares at ~32px pitch, right
   aligned in a 34px utility band that also carries language, font size and skip-to-content.
   Their navy nav bar below holds NO controls — so "in the menu" is not what SEBI does; the
   header band is. */
/* The RIGHT PADDING clears the floating widgets, and it is measured rather than guessed.
   OneTap's circle and the site's translate flag both sit at the top-right and paint over this
   bar — the same corner collision that covered the site's own hamburger on 2026-08-08, when
   OneTap was found covering it at 98% at 320px. Without this reserve the last two swatches are
   unreachable. */
.ust-theme__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 6px 18px;
  max-width: 1400px;
  margin: 0 auto;
  padding: 7px 132px 7px 20px;
}

.ust-theme__legend {
  font-weight: 600;
  white-space: nowrap;
  font-size: 13px;
}

/* PLAIN COLOUR SQUARES. font-size:0 suppresses the abbreviation for sighted users while the
   element and its accessible name stay in the tree. */
.ust-theme__swatch { font-size: 0; }

@media (max-width: 700px) {
  /* On a phone the readout goes first and the skip link shrinks; the swatches and the
     text-size buttons are the reason the bar exists, so they are the last to give ground.
     Measured at 375px: 79px tall, no horizontal overflow, hamburger unobstructed. */
  .ust-theme__inner { padding: 6px 60px 6px 10px; gap: 8px 12px; }
  .ust-theme__skip { font-size: 12px; }
  /* The legend STAYS VISIBLE on a phone. It used to be clipped to 1x1 here, which made the
     plugin's own claim — that this text "names the ACTIVE theme at all times" — false on every
     phone, on the one axis where the swatches lost their letters. Shrunk, not hidden.

     Stacked rather than inline: the legend is ~117px and five 36px swatches are ~204px, which
     does not fit side by side at 375px. Left inline they fought and the swatch row wrapped to
     two lines, taking the bar to 131px. In a column the block is one legend line plus one
     swatch row. */
  .ust-theme__legend { font-size: 11px; font-weight: 600; }
  .ust-theme__colours { flex-direction: column; align-items: flex-end; gap: 3px; }
  .ust-theme__btn { width: 28px; height: 28px; }
}

.ust-theme__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.ust-theme__item { margin: 0; }

/* Compact square, SEBI's shape — but NOT SEBI's hit area.
 *
 * Theirs are 25px, which clears WCAG 2.5.8 Target Size (Minimum, AA in 2.2) by a single pixel
 * and is far under 2.5.5's 44px (AAA), which the earlier pill design met. Matching a reference
 * design does not oblige us to inherit its weakest dimension.
 *
 * 28px, reduced from 36px on 2026-08-15 at Sid's request — smaller squares, more space above and
 * below them, and a shorter band overall. Those pull against each other, so the squares had to
 * lose more than the padding gained: 36 -> 28 frees 8px, of which 4px goes back as padding.
 *
 * 28 IS THE FLOOR AND IT IS NOT ARBITRARY. WCAG 2.5.8 Target Size (Minimum) is 24x24 CSS px,
 * so this keeps 4px of margin over an AA criterion the site is signed against. Going to SEBI's
 * own 25px would clear it by one pixel and leave nothing for a future tweak to eat. */
.ust-theme__btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  background-color: var(--ust-bg-raise, #fff);
  color: inherit;
  border: 1px solid var(--ust-border, #c8d0da);
  border-radius: 0;
  font: inherit;
  cursor: pointer;
}
/* THE CONTROL OWNS ITS OWN APPEARANCE IN EVERY STATE, INCLUDING WITH NO PALETTE ACTIVE.
 *
 * Measured: with no theme selected, tabbing to a control turned its background #ffcd57 —
 * Astra's accent gold — because the site's own button :hover/:focus rules outrank a bare
 * `.ust-theme__btn` (0,1,0). Under a palette our scoped rules win and the leak is invisible,
 * so it only ever showed in the un-themed state, which is the state most visitors are in.
 *
 * The 3px outline was still drawn at ~12:1, so this was never a 2.4.7 failure — the control
 * simply stopped looking like ours. Fixed by specificity, not !important: `.ust-theme` +
 * `.ust-theme__btn` is (0,2,0), which beats the theme's element-and-class button rules while
 * staying easy for a later rule to override deliberately.
 *
 * Every declaration here is colour, and every one is on an element this plugin created.
 */
.ust-theme .ust-theme__btn { border-color: rgba(255, 255, 255, 0.5); }
.ust-theme .ust-theme__btn:hover { border-color: #ffd166; }
/* The ring is #ffd166 rather than --ust-focus because this bar is fixed dark in every palette,
   and the light palettes' focus token is near-black — it would vanish here. Amber on #0b0620
   is 10.4:1. */
.ust-theme .ust-theme__btn:focus-visible {
  outline: 3px solid #ffd166;
  outline-offset: 2px;
  box-shadow: none;
}

/* Active state is carried by THREE independent signals, never colour alone (1.4.1):
   aria-pressed for AT, a heavier border, and a visible check glyph. */
/* ACTIVE STATE — still three independent signals, never colour alone (1.4.1).
 *
 * The text label is visually hidden at this size, so the check glyph that used to ride on it
 * would have disappeared with it. It moves onto the button itself. The other two signals are
 * shape, not hue: a heavier border and an outer ring. A visitor who cannot distinguish the
 * swatch colours still sees which square is selected, and aria-pressed carries it for AT. */
.ust-theme__btn[aria-pressed="true"] {
  border-color: #ffd166;
  border-width: 3px;
  font-weight: 700;
  box-shadow: 0 0 0 2px #0b0620, 0 0 0 3px #ffd166;
}
/* THE CHECK IS INK ON THE SWATCH, so it takes a colour per swatch.
   One amber for all five measured 1.44 / 21 / 1.06 / 1.21 / 1.39:1 — invisible on four of the
   five it was meant to mark, while the code claimed it as one of three independent cues. */
.ust-theme__btn[aria-pressed="true"]::after {
  content: "\2713";
  position: absolute;
  right: 1px;
  bottom: -1px;
  font-size: 12px;
  line-height: 1;
  color: #14141a;
}
.ust-theme__btn[aria-pressed="true"] .ust-theme__swatch[data-ust-swatch="dark"] { color: #ffffff; }
.ust-theme__btn[aria-pressed="true"][data-ust-set="dark"]::after { color: #ffffff; }
/* The label stays in the accessibility tree — visually hidden, never display:none, so the
   button's accessible name is still "Yellow on black" and not "Y". Verified in the a11y tree
   at 320px by probe-controls-keyboard.js. */
.ust-theme__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The swatch previews the palette. It carries the abbreviation as text so the control
   still reads correctly with images off, in forced-colors, and for anyone who cannot
   distinguish the hues — the failure SEBI's empty <a> swatches have. */
/* The swatch now FILLS the button, so the whole 36px square is the palette preview and the
   whole 36px square is the hit target — no inner box, no wasted margin. */
.ust-theme__swatch {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 0;
  font-size: 13px;
  font-weight: 700;
}
.ust-theme__swatch[data-ust-swatch="normal"] { background: #ffffff; color: #1e293b; }
.ust-theme__swatch[data-ust-swatch="dark"]   { background: #000000; color: #ffffff; }
.ust-theme__swatch[data-ust-swatch="yellow"] { background: #ffface; color: #1a1400; }
.ust-theme__swatch[data-ust-swatch="blue"]   { background: #daebff; color: #0a1a2b; }
.ust-theme__swatch[data-ust-swatch="orange"] { background: #ffd1b9; color: #241000; }

.ust-theme__status {
  margin: 0;
  /* Visually hidden, still announced. Never `display:none`, which mutes it. */
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Below 600px the button labels stay visually hidden. They already are at every width in the
   current design, so this block now only guards the narrow case.
   `.ust-theme__legend { width: 100% }` USED TO BE HERE. It dated from the pill design, where
   the legend took its own full row. It outlived that design and silently beat the newer
   `width: 1px` in the 700px block above — which is ordered EARLIER, so this one won — leaving
   the legend 375px wide, absolutely positioned, pushing 111px of horizontal overflow at 375px.
   A 1.4.10 failure introduced by a rule nobody had a reason to look at. */
@media (max-width: 600px) {
  .ust-theme__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .ust-theme__btn[aria-pressed="true"] .ust-theme__label::after { content: none; }
  .ust-theme__btn[aria-pressed="true"] .ust-theme__swatch { box-shadow: 0 0 0 2px currentColor; }
}

/* ------------------------------------------------------------------- print */
/* A persisted dark theme would otherwise print the SEBI-mandated disclosures — the
   grievance table, the 42-table MGT-7 page, the Investor Charter — as black pages.
   Those are exactly the documents a compliance officer prints. Every palette resets
   to black-on-white on paper, and the controls do not print at all. */
@media print {
  :root[data-ust-theme] {
    --ust-bg: #ffffff;
    --ust-bg-alt: #ffffff;
    --ust-bg-raise: #ffffff;
    --ust-fg: #000000;
    --ust-muted: #333333;
    --ust-link: #000000;
    --ust-link-hover: #000000;
    --ust-visited: #000000;
    --ust-border: #000000;
    --ust-accent: #ffffff;
    --ust-on-accent: #000000;
    --ust-plate: #ffffff;
    --ust-on-plate: #000000;
    --ust-focus: #000000;
    /* on-dark / on-dark-link MUST flip to black on paper.
     *
     * They name "text sitting on a band the designer made dark", and their screen values are
     * #ffffff and a light blue. Browsers drop background-colour when printing, so those dark
     * bands come out WHITE — and 138 selectors use these two tokens. Left at their screen
     * values, every one of them prints white-or-pale on white.
     *
     * This block predated the tokens: they were declared in palettes.json, never emitted, and
     * so every rule using them was inert. Defining them fixed 138 live rules on screen and
     * silently opened this hole on paper. A fix that turns dormant rules on has to be
     * re-checked everywhere those rules now reach — print and forced-colors included.
     *
     * assert_tokens_defined.py --print now fails if this block omits any token. */
    --ust-on-dark: #000000;
    --ust-on-dark-link: #000000;
    --ust-focus-alt: #ffffff;
    --ust-error: #8a1f1b;
    color-scheme: light;
  }
  :root[data-ust-theme] :where(html, body) { background: #fff !important; color: #000 !important; }
  .ust-theme { display: none !important; }
}

/* ---------------------------------------------------------- forced-colors */
/* Windows High Contrast and equivalents: the OS palette is the user's decision and
   outranks ours. Stand down completely rather than fight it — but keep the controls
   usable and keep their state legible, since forced-colors discards author colour
   while preserving ARIA. Without this the switcher would claim aria-pressed="true"
   with no visible difference at all. */
@media (forced-colors: active) {
  :root[data-ust-theme] :where(html, body, a, input, select, textarea) {
    background-color: Canvas;
    color: CanvasText;
    border-color: CanvasText;
  }
  :root[data-ust-theme] :where(a) { color: LinkText; }
  .ust-theme__btn { border-color: ButtonBorder; }
  .ust-theme__btn[aria-pressed="true"] {
    border-color: Highlight;
    forced-color-adjust: none;
    outline: 2px solid Highlight;
  }
  .ust-theme__swatch { forced-color-adjust: none; }
}

/* --------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  .ust-theme, .ust-theme * { transition: none !important; animation: none !important; }
}

/* ===========================================================================
 * THE STRIP DISPLACES THE HEADER, AND ON ONE PAGE THAT PUT IT UNDER A MODAL.
 *
 * Found on production, 2026-08-14, minutes after deploying 0.5.2. On
 * /terms-and-conditions/ at 375px the mobile menu became unreachable: tapping the
 * hamburger did nothing, aria-expanded stayed false, the dropdown stayed at 0px.
 *
 * WHY. That page renders its own body copy inside a PERMANENTLY OPEN Elementor
 * lightbox — `.dialog-widget.dialog-lightbox-widget`, position:fixed, z-index:9999,
 * display:flex, no close button, containing "IMPORTANT: YOU MUST READ AND...". Its
 * wrapper is pointer-events:none, but its content box (y 114-686 at 375px) is
 * pointer-events:all.
 *
 * The lightbox is FIXED (viewport-relative). The site header is IN FLOW. So our
 * 105px strip moves the header down and the lightbox does not move at all — the
 * header lands inside the lightbox's content box, and the lightbox, being z-9999
 * against the header's z-999, correctly wins the tap.
 *
 * MEASURED, 3 runs per arm, on the live page:
 *     our strip (105px)        toggle y=124   menu DEAD   0px -> 0px
 *     strip removed            toggle y=20    menu opens  0px -> 8000px
 *     NEUTRAL 105px spacer     toggle y=125   menu DEAD   0px -> 0px
 *     our strip, height 0      toggle y=20    menu opens  0px -> 8000px
 *
 * The neutral-spacer arm is the important one: ANY offset does this, so it is not
 * our styling. We triggered a latent condition rather than authoring a new one —
 * which changes the right fix, not the obligation to make it.
 *
 * THE TRADE-OFF, STATED. Raising the header above 9999 means the header will also
 * paint above a genuinely-open Elementor lightbox. On this site that mechanism is
 * used to render page content rather than image galleries, and a header floating
 * over a lightbox is cosmetic where dead navigation is not. Scoped to the sibling
 * relation so it can only ever apply where OUR strip did the displacing: with the
 * plugin deactivated, the selector matches nothing and the page is untouched.
 *
 * Content integrity verified separately at 375px and 1280px: the lightbox box,
 * its 5,815 characters and all 25 visible paragraphs are identical with and
 * without this rule. The rule changes paint order and nothing else.
 * =========================================================================== */
.ust-theme ~ header.elementor-location-header > .elementor-element {
  z-index: 10000;
}
