/*
 * tests.css — HTML integrity & accessibility tests for Weblin.
 *
 * A development-only stylesheet (based on Heydon Pickering's REVENGE.CSS /
 * "Testing HTML With Modern CSS" technique). It flags common markup
 * anti-patterns in the browser with a visual outline and a DevTools-readable
 * custom property (`--error-*` / `--warning-*`) you can inspect on the element.
 *
 * Usage:
 *   <link rel="stylesheet" href="css.css">
 *   <link rel="stylesheet" href="tests.css">   <!-- dev only; drop in production -->
 *
 * To also render an on-page message chip next to each flagged element:
 *   <html lang="en" data-tests-labels>
 *
 * Pure CSS — no JS. Errors use a pink outline, warnings an amber one.
 */

html {
  --error-outline: 3px solid #ff3b6b;
  --warning-outline: 3px solid #ffb020;
}

/* ---- anchors ------------------------------------------------------- */
a:not([href]) {
  outline: var(--error-outline); outline-offset: 2px;
  --error-anchor-no-href: 'Links need an href (use <button> for actions)';
  --label: 'link without href';
}
a[href=""] {
  outline: var(--error-outline); outline-offset: 2px;
  --error-anchor-empty-href: 'The href is empty';
  --label: 'empty href';
}
a[href$="#"] {
  outline: var(--error-outline); outline-offset: 2px;
  --error-anchor-fragment: 'The href is an unnamed fragment (href="#")';
  --label: 'unnamed fragment';
}
a[href^="javascript:"] {
  outline: var(--error-outline); outline-offset: 2px;
  --error-anchor-javascript: 'javascript: href — use <button> for actions';
  --label: 'javascript: href';
}
a[disabled] {
  outline: var(--error-outline); outline-offset: 2px;
  --error-anchor-disabled: 'disabled is not valid on anchors — use <button>';
  --label: 'disabled anchor';
}

/* ---- labels -------------------------------------------------------- */
label:not(:has(:is(input, output, textarea, select))):not([for]) {
  outline: var(--error-outline); outline-offset: 2px;
  --error-label-unassociated: 'The <label> neither uses for= nor wraps a control';
  --label: 'unassociated label';
}

/* ---- orphan inputs (warning: outside a <form>) -------------------- */
input:not(form input) {
  outline: var(--warning-outline); outline-offset: 2px;
  --warning-input-orphan: 'The input is outside a <form>';
}

/* ---- figure / figcaption ------------------------------------------ */
figcaption:not(figure > figcaption) {
  outline: var(--error-outline); outline-offset: 2px;
  --error-figcaption-not-child: 'The <figcaption> is not a direct child of a <figure>';
  --label: 'figcaption outside figure';
}
figcaption:empty {
  outline: var(--error-outline); outline-offset: 2px;
  --error-figcaption-empty: 'The <figcaption> is empty';
  --label: 'empty figcaption';
}
figure:not(:is([aria-label], [aria-labelledby])):not(:has(figcaption)) {
  outline: var(--error-outline); outline-offset: 2px;
  --error-figure-unlabeled: 'The <figure> is not labeled (no figcaption, aria-label or aria-labelledby)';
  --label: 'unlabeled figure';
}
figure[aria-label]:not(:has(figcaption)) {
  outline: var(--warning-outline); outline-offset: 2px;
  --warning-figure-invisible-label: 'The figure label (aria-label) is invisible to sighted users';
  --label: 'invisible figure label';
}
figure[aria-label] figcaption {
  outline: var(--warning-outline); outline-offset: 2px;
  --warning-figure-overridden-caption: 'The figcaption is overridden by an aria-label';
  --label: 'figcaption overridden by aria-label';
}
figure > figcaption ~ figcaption {
  outline: var(--error-outline); outline-offset: 2px;
  --error-figure-two-captions: 'A <figure> has two figcaptions';
  --label: 'two figcaptions';
}

/* ---- breadcrumbs outside a labeled <nav> -------------------------- */
ol[class*="breadcrumb"]:not(:is(nav[aria-label], nav[aria-labelledby]) ol) {
  outline: var(--error-outline); outline-offset: 2px;
  --error-breadcrumbs-undiscoverable: 'Breadcrumbs are outside a labeled <nav> landmark';
  --label: 'breadcrumbs outside nav';
}

/* ---- content outside landmarks ------------------------------------ */
body :not(:is(header, nav, main, aside, footer, script, style, noscript, template)):not(:is(header, nav, main, aside, footer) *):not(.skip-link) {
  outline: var(--error-outline); outline-offset: 2px;
  --error-content-outside-landmark: 'Content is not inside a landmark (header, nav, main, aside, footer)';
  --label: 'content outside landmark';
}

/* ---- misc usability ------------------------------------------------- */
:is(div > div > div > div > *) {
  outline: var(--warning-outline); outline-offset: 2px;
  --warning-divitis: 'Excessive div nesting — is the layout really that deep?';
  --label: 'divitis';
}
header nav:has(ul > ul) {
  outline: var(--warning-outline); outline-offset: 2px;
  --warning-nested-nav: 'Nested navigation in the header is hard to traverse';
  --label: 'nested header nav';
}

/* ---- Weblin-specific ---------------------------------------------- */
img:not([alt]) {
  outline: var(--error-outline); outline-offset: 2px;
  --error-img-no-alt: 'The <img> has no alt attribute';
}
button:not([type]) {
  outline: var(--warning-outline); outline-offset: 2px;
  --warning-button-no-type: 'The <button> has no type — it defaults to submit';
  --label: 'button without type';
}
button:empty {
  outline: var(--warning-outline); outline-offset: 2px;
  --warning-button-empty: 'The <button> is empty — no accessible name';
  --label: 'empty button';
}

/* ---- on-page message chips (opt-in) -------------------------------- */
html[data-tests-labels] :is(
  a:not([href]), a[href=""], a[href$="#"], a[href^="javascript:"], a[disabled],
  label:not(:has(:is(input, output, textarea, select))):not([for]),
  figcaption:not(figure > figcaption), figcaption:empty,
  figure:not(:is([aria-label], [aria-labelledby])):not(:has(figcaption)),
  figure[aria-label]:not(:has(figcaption)),
  figure > figcaption ~ figcaption,
  ol[class*="breadcrumb"]:not(:is(nav[aria-label], nav[aria-labelledby]) ol),
  body :not(:is(header, nav, main, aside, footer, script, style, noscript, template)):not(:is(header, nav, main, aside, footer) *):not(.skip-link),
  :is(div > div > div > div > *),
  header nav:has(ul > ul),
  button:not([type]), button:empty
)::after {
  content: var(--label, '');
  display: inline-block;
  margin-inline-start: 6px;
  padding: 1px 6px;
  border-radius: 4px;
  background: #ff3b6b;
  color: #fff;
  font: 11px/1.5 system-ui, sans-serif;
  vertical-align: middle;
  white-space: nowrap;
}
