/*
 * app.css -- pbrs_manager
 *
 * A dense operational tool, not a dashboard: table rows are 36px so eleven
 * devices fit the screen without scrolling, the toolbar is one row, page
 * headings stay small. No metric tiles, no equal card grids as a lead, no
 * coloured side stripes, no glass, no shadow at rest -- see DESIGN.md and
 * PRODUCT.md for the reasoning.
 *
 * No colour literal in this file. Every colour is var(--color-*) or
 * var(--shadow-float) from tokens.css, which is loaded before this file.
 */

/* ================= fonts, self hosted ================= */
@font-face {
  font-family: 'Familjen Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/familjen-grotesk-variable.woff2') format('woff2');
}

@font-face {
  font-family: 'Martian Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url('../fonts/martian-mono-variable.woff2') format('woff2');
}

/* ================= reset ================= */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--text-15);
  line-height: 1.5;
  font-kerning: normal;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* The page body never scrolls sideways; a wide table scrolls inside its
     own container (.table-scroll) instead. */
  overflow-x: hidden;
}

img,
svg {
  max-width: 100%;
}

a {
  color: inherit;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 600;
  line-height: 1.25;
}

/* Design principle: an administrative page needs room for rows, not a
   headline. Headings stay small and quiet everywhere. */
h1 {
  font-size: var(--text-17);
}

h2 {
  font-size: var(--text-15);
  color: var(--color-text-2);
}

p {
  margin: 0;
  max-width: 70ch;
}

ul,
ol {
  margin: 0;
  padding: 0;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

/* ================= focus ================= */
/* Visible, separate from hover, and always the brand accent -- DESIGN.md
   gives the accent exactly three jobs: active tab, primary button, focus
   ring. This is the third. */
:focus {
  outline: none;
}

:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ================= helpers ================= */
.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ================= application shell ================= */
.app-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.app-header {
  display: flex;
  align-items: center;
  gap: var(--space-24);
  min-height: var(--header-height);
  padding: 0 var(--space-16);
  background: var(--color-surface);
  border-bottom: var(--border-width) solid var(--color-border);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  text-decoration: none;
  flex-shrink: 0;
  color: var(--color-text);
}

.brand__mark {
  width: 1.5rem;
  height: 1.5rem;
  flex-shrink: 0;
}

.brand__name {
  font-family: var(--font-mono);
  font-size: var(--text-13);
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--color-text-2);
}

.app-nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex: 1;
  min-width: 0;
  overflow-x: auto;
}

.app-nav__link {
  display: inline-flex;
  align-items: center;
  padding: var(--space-8) var(--space-12);
  border-radius: var(--radius-md);
  font-size: var(--text-13);
  font-weight: 500;
  color: var(--color-text-2);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}

.app-nav__link:hover {
  background: var(--color-surface-2);
  color: var(--color-text);
}

.app-nav__link[aria-current="page"] {
  background: var(--color-surface-2);
  color: var(--color-accent);
}

.app-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  flex-shrink: 0;
}

/* ================= data source indicator ================= */
.data-source {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  font-family: var(--font-mono);
  font-size: var(--text-12);
  color: var(--color-text-3);
  white-space: nowrap;
}

.data-source__dot {
  width: 0.45em;
  height: 0.45em;
  border-radius: 50%;
  background: var(--color-good);
  flex-shrink: 0;
}

/* Stale vendor data is dampened, never hidden and never dressed up as
   fresh -- PRODUCT.md forbids invented freshness. */
.data-source--stale .data-source__dot {
  background: var(--color-warning);
}

.data-source--stale .data-source__label {
  color: var(--color-text-3);
}

/* ================= theme switch ================= */
.theme-switch {
  display: inline-flex;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.theme-switch__option {
  padding: var(--space-4) var(--space-12);
  border: none;
  border-right: var(--border-width) solid var(--color-border);
  background: transparent;
  color: var(--color-text-2);
  font-size: var(--text-12);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}

.theme-switch__option:last-child {
  border-right: none;
}

.theme-switch__option:hover {
  background: var(--color-surface-2);
  color: var(--color-text);
}

.theme-switch__option[aria-pressed="true"] {
  background: var(--color-surface-2);
  color: var(--color-accent);
}

/* ================= icon button (settings gear) ================= */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--radius-md);
  color: var(--color-text-2);
  text-decoration: none;
  transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}

.icon-btn svg {
  width: 1.1rem;
  height: 1.1rem;
}

.icon-btn:hover {
  background: var(--color-surface-2);
  color: var(--color-text);
}

.icon-btn[aria-current="page"] {
  color: var(--color-accent);
  background: var(--color-surface-2);
}

.app-signout {
  display: inline-flex;
  margin: 0;
}

/* ================= subnav ================= */
.subnav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-8) var(--space-16);
  background: var(--color-surface);
  border-bottom: var(--border-width) solid var(--color-border);
}

.subnav nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.subnav a {
  display: inline-flex;
  align-items: center;
  padding: var(--space-4) var(--space-12);
  border-radius: var(--radius-md);
  font-size: var(--text-13);
  color: var(--color-text-2);
  text-decoration: none;
  transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}

.subnav a:hover {
  background: var(--color-surface-2);
  color: var(--color-text);
}

.subnav a[aria-current="page"] {
  background: var(--color-surface-2);
  color: var(--color-accent);
}

/* ================= content ================= */
.app-main {
  flex: 1;
  padding: var(--space-24) var(--space-16);
  max-width: var(--content-max-width);
  width: 100%;
  margin: 0 auto;
}

.app-main > * + * {
  margin-top: var(--space-24);
}

/* ================= toolbar: one row ================= */
.toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-8);
}

.toolbar > * {
  flex-shrink: 0;
}

.toolbar input[type="search"],
.toolbar input[type="text"] {
  flex: 0 1 22rem;
  min-width: 10rem;
  /* The search box used to fall back to the browser default, which renders as
     a bright box on a dark page. It carries the same skin as every other
     input now. */
  padding: var(--space-8) var(--space-12);
  color: var(--color-text);
  background: var(--color-surface-2);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-md);
  font: inherit;
  font-size: var(--text-15);
}
.toolbar input[type="search"]::placeholder,
.toolbar input[type="text"]::placeholder { color: var(--color-text-3); }

/* ================= table ================= */
.table-scroll {
  overflow-x: auto;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
}

.table {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  font-size: var(--text-13);
}

.table thead th {
  position: sticky;
  top: 0;
  background: var(--color-surface-2);
  text-align: left;
  padding: 0;
  border-bottom: var(--border-width-strong) solid var(--color-border-strong);
  white-space: nowrap;
}

/* Rows are exactly 36px, so eleven devices fit one screen without
   scrolling -- PRODUCT.md, "density is a function, not a stinginess". */
.table td,
.table tbody th {
  height: var(--row-height);
  padding: 0 var(--space-12);
  border-bottom: var(--border-width) solid var(--color-border);
  color: var(--color-text-2);
  vertical-align: middle;
}

.table tbody th {
  text-align: left;
  color: var(--color-text);
  font-weight: 500;
}

.table tbody tr:last-child td,
.table tbody tr:last-child th {
  border-bottom: none;
}

/* Rows tell apart by alternating surface brightness, not by a rule between
   every line (DESIGN.md). */
.table tbody tr:nth-child(even) {
  background: var(--color-surface);
}

.table tbody tr:hover {
  background: var(--color-surface-2);
}

.table .col-mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
}

.table__sort {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  height: var(--row-height);
  padding: 0 var(--space-12);
  border: none;
  background: transparent;
  cursor: pointer;
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--text-12);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-3);
  text-align: left;
}

.table__sort:hover {
  color: var(--color-text);
}

.table__sort-icon {
  display: inline-block;
  width: 0.7em;
  text-align: center;
  opacity: 0.35;
}

th[aria-sort] .table__sort {
  color: var(--color-accent);
}

th[aria-sort] .table__sort-icon {
  opacity: 1;
}

th[aria-sort="ascending"] .table__sort-icon::before {
  content: '\2191';
}

th[aria-sort="descending"] .table__sort-icon::before {
  content: '\2193';
}

th:not([aria-sort]) .table__sort-icon::before {
  content: '\2195';
}

/* ================= status pill ================= */
/* Word plus dot, always both -- colour alone never carries the state
   (PRODUCT.md accessibility rule; red and green side by side are not
   distinguishable for one in twelve men). */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  padding: var(--space-4) var(--space-12);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--text-12);
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.5;
  white-space: nowrap;
  color: var(--color-text-2);
}

.pill__dot {
  width: 0.55em;
  height: 0.55em;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

.pill--good {
  color: var(--color-good);
  border-color: color-mix(in oklch, var(--color-good) 45%, var(--color-border));
}

.pill--warning {
  color: var(--color-warning);
  border-color: color-mix(in oklch, var(--color-warning) 45%, var(--color-border));
}

.pill--critical {
  color: var(--color-critical);
  border-color: color-mix(in oklch, var(--color-critical) 45%, var(--color-border));
}

.pill--neutral {
  color: var(--color-unknown);
}

/* ================= view switch (table / tiles) ================= */
.view-switch {
  display: inline-flex;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.view-switch__option {
  padding: var(--space-8) var(--space-16);
  border: none;
  border-right: var(--border-width) solid var(--color-border);
  background: transparent;
  color: var(--color-text-2);
  font-size: var(--text-13);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}

.view-switch__option:last-child {
  border-right: none;
}

.view-switch__option:hover {
  background: var(--color-surface-2);
}

.view-switch__option[aria-pressed="true"] {
  background: var(--color-surface-2);
  color: var(--color-accent);
}

.view[hidden] {
  display: none;
}

/* ================= tile view ================= */
/* The same rows as the table, reshaped for a glance -- not a marketing
   card grid: no shadow, no gradient, no icon-plus-heading filler. */
.tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--space-12);
}

.tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  padding: var(--space-12);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
}

.tile__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-8);
}

.tile__id {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-15);
  font-weight: 500;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}

.tile__subtitle {
  margin: 0;
  color: var(--color-text-3);
  font-size: var(--text-13);
}

.tile__body {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-4) var(--space-12);
  font-size: var(--text-13);
}

.tile__body dt {
  color: var(--color-text-3);
}

.tile__body dd {
  margin: 0;
  color: var(--color-text-2);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* ================= form field ================= */
.field {
  display: grid;
  gap: var(--space-8);
  max-width: 28rem;
}

.field__label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-8);
  font-size: var(--text-13);
  font-weight: 500;
  color: var(--color-text-2);
}

.field__optional {
  font-family: var(--font-mono);
  font-size: var(--text-12);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-3);
}

.field__control {
  padding: var(--space-8) var(--space-12);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-md);
  color: var(--color-text);
  font-family: var(--font-sans);
  transition: border-color var(--duration-fast) var(--ease-out);
}

.field__control:hover {
  border-color: var(--color-text-3);
}

.field__control:focus-visible {
  border-color: var(--color-accent);
}

.field--invalid .field__control {
  border-color: var(--color-critical);
}

.field__error {
  display: flex;
  align-items: baseline;
  gap: var(--space-4);
  font-size: var(--text-12);
  color: var(--color-critical);
}

.field__hint {
  font-size: var(--text-12);
  color: var(--color-text-3);
}

/* ================= buttons ================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  padding: var(--space-8) var(--space-16);
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--text-13);
  line-height: 1.4;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out), opacity var(--duration-fast) var(--ease-out);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.55;
  pointer-events: none;
}

.btn--primary {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-bg);
}

.btn--primary:hover {
  opacity: 0.88;
}

.btn--secondary {
  background: transparent;
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.btn--secondary:hover {
  background: var(--color-surface-2);
}

.btn--danger {
  background: transparent;
  border-color: var(--color-critical);
  color: var(--color-critical);
}

.btn--danger:hover {
  background: color-mix(in oklch, var(--color-critical) 12%, transparent);
}

.btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--color-text-2);
}

.btn--ghost:hover {
  background: var(--color-surface-2);
  color: var(--color-text);
}

/* ================= empty state ================= */
.empty-state {
  padding: var(--space-32) var(--space-16);
  text-align: center;
  color: var(--color-text-3);
  font-size: var(--text-13);
}

/* ================= age ================= */
.age {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-2);
  transition: opacity var(--duration-base) var(--ease-out);
}

/* Past ten minutes, vendor data is dampened rather than hidden --
   PRODUCT.md: "age of the data is part of the data". */
.age--old {
  opacity: 0.6;
  color: var(--color-text-3);
}

/* ================= floating elements ================= */
/* The one shadow in the application. Nothing at rest uses it; reserved
   for things that actually float above the page, e.g. an open menu. */
.elevated {
  box-shadow: var(--shadow-float);
}

/* ================= motion reduction ================= */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}


/* --- header fits on one line ------------------------------------------
   Eight tabs plus the controls did not fit at 1491 pixels and the tab bar
   grew its own scrollbar. The controls now carry icons instead of words,
   and the tab labels give up a little room before the bar does. */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.app-nav { overflow: visible; min-width: 0; }

.app-nav__link {
  padding-inline: var(--space-8);
  font-size: var(--text-13);
  white-space: nowrap;
}

.theme-switch__option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  padding: 0;
}
.theme-switch__option svg { width: 15px; height: 15px; }

.app-header__actions { gap: var(--space-8); }

.data-source__label { font-size: var(--text-12); }

@media (max-width: 980px) {
  .data-source__label { display: none; }
}


/* The mark is a picture now, changeable from the settings page, so it needs
   a fixed box instead of inheriting a drawing's own size. */
img.brand__mark {
  width: 26px;
  height: 26px;
  object-fit: contain;
  display: block;
}
