/**
 * The shared skin: everything the status page and the operator's GUI both need,
 * expressed entirely in the client's theme tokens (`theme.js`).
 *
 * Nothing in this file names a colour. That is the whole point — a colour named
 * here would be a third palette, which is the thing M6.8 exists to remove. If a
 * rule below needs a shade the token vocabulary does not have, the answer is a
 * token in every theme, not a hex code here.
 *
 * The tokens are set on `:root` by theme.js at load, so the values below are
 * fallbacks for the fraction of a second before that runs and for the case
 * where the script is blocked. They are the default theme's, so a page with no
 * JavaScript at all is still Cinematic Orange rather than unstyled.
 */

:root {
  --theme-font-family: ui-rounded, "SF Pro Rounded", "Avenir Next", "Segoe UI", Roboto, system-ui, sans-serif;
  --theme-app-background: linear-gradient(145deg, #020202 0%, #0b0b0b 56%, #000000 100%);
  --theme-surface-background: linear-gradient(145deg, #1a1a1a 0%, #0d0d0d 100%);
  --theme-text-primary: #f4f6fa;
  --theme-text-muted: #929292;
  --theme-border-solid: #292929;
  --theme-accent-solid: #e68424;
  --theme-button-radius: 10px;
  --theme-banner-radius: 16px;
  --theme-logo-filter: none;
  --theme-header-background-color: #101010;
  --theme-header-background-image: repeating-conic-gradient(#000000 0% 25%, #1a1a1a 0% 50%);
  --theme-header-background-position: 0 0, 6px 6px;
  --theme-header-background-size: 12px 12px;

  /* Not theme tokens: the measurements every screen here shares. Kept beside
     the palette because they are the other thing that must not be re-invented
     per file. */
  --brand-line: 1px solid var(--theme-border-solid);
  --brand-shell: 1400px;
  /* The header logo's width, matching the client's `--app-logo-width` exactly.
     One measurement, because the operator moves between the two surfaces and a
     logo that changes size between them reads as two different products. */
  --brand-logo-width: 187.85px;
  /* The asset here is the *Server* lockup — the same wordmark with the rack
     icon and the word "Server" after a rule — so it is 1314:148 where the
     client's is 560:110. Sizing it to `--brand-logo-width` would shrink the
     shared half of the artwork to two thirds of the size it is on the client,
     which is the drift that measurement exists to prevent. This is that same
     measurement scaled by the ratio of the two crops (1314/781, 781px being the
     head-and-wordmark span inside the lockup), so the wordmark lands at exactly
     the client's size and the suffix is what makes the asset wider. This is the
     lockup at full size: the sign-in card, where the logo is the screen's whole
     subject and has a card built around it. */
  --brand-logo-lockup-width: 316.05px;
  /* The nav's smaller instance of the same lockup. A header is a place you look
     past, not at, and at full size the logo took a fifth of the bar and pushed
     the four buttons towards the middle of the window. Deliberately its own
     measurement rather than a percentage of the one above, so changing what the
     sign-in shows does not silently resize the chrome on every screen. */
  --brand-logo-nav-width: 240px;
  /* The lockup's own ratio, so a box can be reserved for it before it loads.
     8.88:1 for the Server row.

     These last three are the only per-product measurements in this file, and a
     product directory's `product.css` overrides exactly them (scripts/brand.js
     generates it from the crop, so the numbers cannot drift from the artwork).
     They stay here as the Server values rather than moving out, so that a
     missing or unbuilt product directory renders at Server proportions instead
     of collapsing an unsized image to nothing. */
  --brand-logo-aspect: 1314 / 148;

  /* What the client actually paints its nav items, which is not what its own
     token says. `.main-nav-item` asks for `--theme-text-secondary`, a lighter grey,
     but the markup carries a Tailwind utility built from `tv-text-secondary` in
     `tailwind.config.js` — a flat #a0a0a0 that no theme touches — and the
     utility wins. So the shade an operator sees on the client's bar is this one,
     and the bar beside it has to be the same or the two chrome rows read as two
     applications. Named here rather than reached for as a token because it is
     not a token there either; if the client ever makes it one, this becomes a
     `var()` and nothing else changes. Daylight takes its own text colour
     instead: a mid grey that reads as secondary on black is illegible on paper.
   */
  --brand-nav-text: #a0a0a0;

  /* The bar's height, and the offset a sticky table header parks at — one value
     because they are one measurement: a `th` that stops anywhere but the underside
     of the bar either tucks under it or floats below it with a stripe of scrolling
     rows showing through. 60px is the client's own header at the window sizes this
     GUI is used at (`--app-header-height` inside the 1320/740 query, the same one
     that sets the nav's 15px). */
  --brand-nav-height: 60px;

  /* The nav's pills. Not `--theme-button-radius`: that is a *button's* radius,
     8–14px depending on the theme, and at nav size it rounds a short word like
     "Users" into a lozenge. One shared value so the pills and the gear beside
     them are the same shape whatever theme is on. */
  --brand-nav-radius: 6px;

  /* Nor are these. The client's vocabulary has an accent and a focus colour but
     no *state* colours, because the app never has to say "this subtitle stops
     at 17% of the runtime". They are the one thing this file is allowed to name,
     they are named once, and the only theme that has to restate them is the
     light one — where amber and green on white are illegible at 12px. */
  --brand-ok: #3ddc97;
  --brand-warn: #e0a63a;
  --brand-bad: #e56a6a;

  /* Shadows are the one thing that is black in every theme, light included —
     a shadow is absence of light, not a colour. Named so that no stylesheet
     downstream has to write a literal to cast one. */
  --brand-shadow: 0 10px 30px rgb(0 0 0 / 30%);
  --brand-shadow-lift: 0 18px 50px rgb(0 0 0 / 28%);
}

:root[data-theme="daylight"] {
  --brand-nav-text: var(--theme-text-secondary);
  --brand-ok: #12784f;
  --brand-warn: #96620a;
  --brand-bad: #b3261e;
}

* { box-sizing: border-box; }

/* Every screen the GUI shows or hides is toggled with `el.hidden`, and some of
   the things toggled that way also carry a class that sets `display`. An author
   rule beats the browser's own `[hidden] { display: none }` whatever its
   specificity, so without this line `hidden = true` sets the attribute and
   changes nothing — which once left a signed-in operator staring at the sign-in
   form with the whole app rendered below the fold. `!important` rather than
   reordering, because the next class with a `display` in it must not be able to
   reintroduce it. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--theme-app-background);
  background-attachment: fixed;
  color: var(--theme-text-primary);
  font-family: var(--theme-font-family);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--theme-link, var(--theme-accent-solid)); text-decoration: none; }
a:hover { text-decoration: underline; }

/* The mark is a gradient glyph, so it survives any theme on its own; the filter
   is what lets a theme tune it — the client uses the same token to tint the logo
   for Halloween and Christmas, and Daylight uses it to darken the mark a shade
   against paper. Both surfaces share this rule so the logo can never be treated
   twice. */
.brand-mark, img[src*="catniptv-"] { filter: var(--theme-logo-filter); }

/* The full logo is the one asset a filter cannot rescue on a light ground: its
   "catn" and its "Server" are set in white and simply disappear, and inverting
   it would take the orange ramp to cyan. `scripts/brand.js` bakes an ink-wordmark copy for exactly
   this, and the swap is a `content:` url — the same mechanism the client uses to
   swap its own header logo. Scoped to Daylight by name rather than to a media
   query, because the theme is a choice and may not match the operating system. */
:root[data-theme="daylight"] img[src$="catniptv-logo.png"] {
  content: url("/brand/catniptv-logo-ink.png");
}

/* One focus treatment for the whole product. Keyboard only — `:focus-visible`,
   not `:focus` — because a mouse click on a button should not leave a ring
   sitting there, and an operator tabbing a form has to be able to see where
   they are without hunting. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--theme-focus-solid, var(--theme-accent-solid));
  outline-offset: 2px;
  border-radius: 4px;
}

/* ---- controls ----------------------------------------------------------- */

/* The half of a form the page does not draw: the list a `select` drops down, the
   calendar an `input[type=date]` opens, the scrollbars. Those are the browser's
   own widgets, and left alone it draws them in the platform's light grey — a
   panel of Windows chrome hanging off a black page.
 *
 * `color-scheme` is the only handle CSS has on them, and it takes a keyword
 * rather than a colour, which is exactly right here: the point is not to paint
 * the popup (nothing can) but to tell the browser which of its two paintings to
 * use. Every theme in the registry is dark but one, so `dark` is the default and
 * Daylight names itself out of it. `background-color` on an `option` is honoured
 * in some browsers, but every theme's surface token is a gradient and a popup
 * will not take one — so this is the whole of the fix, not half of it. */
:root { color-scheme: dark; }
:root[data-theme="daylight"] { color-scheme: light; }

input, select, textarea, button {
  font: inherit;
  font-family: var(--theme-font-family);
  color: var(--theme-text-primary);
  background: var(--theme-input-background, var(--theme-surface-background));
  border: var(--brand-line);
  border-radius: 6px;
  padding: 7px 9px;
}
input::placeholder, textarea::placeholder { color: var(--theme-text-muted); }
input:hover, select:hover, textarea:hover { border-color: var(--theme-border-strong-solid, var(--theme-border-solid)); }
input[type="checkbox"], input[type="radio"] {
  width: auto;
  justify-self: start;
  accent-color: var(--theme-accent-solid);
}

button {
  background: var(--theme-button-background, var(--theme-highlight-paint));
  border-color: transparent;
  border-radius: var(--theme-button-radius);
  color: var(--theme-button-text, var(--theme-text-inverse));
  font-weight: 600;
  cursor: pointer;
}
button:hover:not(:disabled) { background: var(--theme-button-hover-background, var(--theme-highlight-hover-paint)); }
button.ghost {
  background: var(--theme-button-secondary-background);
  color: var(--theme-text-primary);
  border: var(--brand-line);
  font-weight: 500;
}
button.ghost:hover:not(:disabled) { background: var(--theme-button-secondary-hover-background); }
button.danger {
  background: var(--theme-button-secondary-background);
  color: var(--brand-bad);
  border: var(--brand-line);
  font-weight: 500;
}
button:disabled { opacity: .45; cursor: default; }

/* ---- surfaces ----------------------------------------------------------- */

.card {
  background: var(--theme-surface-background);
  border: var(--brand-line);
  border-radius: var(--theme-banner-radius);
  padding: 20px;
}

.muted { color: var(--theme-text-muted); }
.section { color: var(--theme-text-section); }
