/* ==========================================================================
   base.css , self-hosted fonts + element defaults + the global focus ring
   ==========================================================================
   NO HEX VALUES IN THIS FILE. See tokens.css.
   ========================================================================== */


/* ==========================================================================
   @font-face , SELF-HOSTED. No fonts.googleapis.com.
   ==========================================================================
   v1 pulled 3 families (Inter was not one of them: Nunito, Roboto, JetBrains
   Mono) from Google's CDN with a render-blocking <link>, on a private admin
   console behind a login. Two of the three were never used by the default
   theme. That is a third-party dependency, a privacy leak, and a hard
   failure mode if Google is unreachable, in exchange for nothing.

   Now: 2 families, 3 files, 522 KB, served from our own nginx with
   immutable cache headers. Fetched once, then never again.

   @font-face sits OUTSIDE @layer deliberately. At-rules like @font-face are
   not affected by layering, and keeping them out makes that explicit.

   font-display:swap => text paints immediately in the fallback face and
   swaps when the webfont lands. No invisible-text flash.
   ========================================================================== */

@font-face {
  font-family: "Inter";
  src: url("/static/fonts/InterVariable.woff2") format("woff2-variations");
  font-weight: 100 900;          /* ONE file covers the entire weight range */
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/static/fonts/JetBrainsMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/static/fonts/JetBrainsMono-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}


@layer base {

  /* ------------------------------------------------------------------------
     DOCUMENT
     ------------------------------------------------------------------------ */
  html {
    font-family: var(--font-ui);
    font-size: 100%;             /* respect the user's browser font size */
  }

  body {
    background-color: var(--color-bg);
    color: var(--color-text);
    font-size: var(--fs-3);
    font-weight: var(--fw-regular);
    line-height: var(--lh-base);
    letter-spacing: var(--tracking-normal);
    /* Colour changes must not lag behind a theme switch. */
    transition: background-color var(--dur-base) var(--ease-out),
                color var(--dur-base) var(--ease-out);
  }


  /* ------------------------------------------------------------------------
     TYPOGRAPHY , every size comes from the 7-step scale. No exceptions.

     Mono is used for headings and numbers because that IS the cyberpunk
     identity the operator wants kept. Body copy is Inter because mono at
     14px in long runs is what made v1 unreadable.
     ------------------------------------------------------------------------ */
  h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-mono);
    font-weight: var(--fw-bold);
    line-height: var(--lh-tight);
    color: var(--color-text);
  }

  h1 { font-size: var(--fs-7); letter-spacing: var(--tracking-tight); }
  h2 { font-size: var(--fs-6); letter-spacing: var(--tracking-tight); }
  h3 { font-size: var(--fs-5); }
  h4 { font-size: var(--fs-4); }
  h5 { font-size: var(--fs-3); }
  h6 { font-size: var(--fs-2); letter-spacing: var(--tracking-wide); text-transform: uppercase; }

  p { line-height: var(--lh-base); }

  small { font-size: var(--fs-1); }

  strong, b { font-weight: var(--fw-semibold); }

  code, kbd, samp, pre {
    font-family: var(--font-mono);
    font-size: 0.925em;          /* relative: keeps mono optically level with Inter */
  }

  code {
    background-color: var(--color-bg-sunken);
    border: var(--bw-hair) solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0.1em 0.4em;
    color: var(--color-accent);
  }

  pre {
    background-color: var(--color-bg-sunken);
    border: var(--bw-hair) solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--sp-4);
    overflow-x: auto;            /* code scrolls itself, page never does */
  }
  pre code {
    background: none;
    border: none;
    padding: 0;
  }

  /* Numeric readouts. Tabular figures stop stat values jittering as they
     tick, which v1 did on every 5-second poll. */
  .num, td.num, .stat-value {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
  }


  /* ------------------------------------------------------------------------
     LINKS
     ------------------------------------------------------------------------ */
  a {
    color: var(--color-accent);
    text-decoration: none;
    text-underline-offset: 0.2em;
    transition: color var(--dur-fast) var(--ease-out);
  }
  a:hover {
    color: var(--color-accent-hover);
    text-decoration: underline;
  }


  /* ------------------------------------------------------------------------
     THE FOCUS RING , THE SINGLE MOST IMPORTANT A11Y RULE IN THIS REBUILD
     ------------------------------------------------------------------------
     v1 measured: 0 :focus rules, 0 :focus-visible rules, 0 tabindex.
     Keyboard navigation was completely invisible. You could tab through the
     whole dashboard and never know where you were.

     :focus-visible (not :focus) means mouse users never see a ring on click,
     but keyboard and switch users always do. Orange, because it is the one
     hue guaranteed to sit on top of a cyan/magenta palette without being
     mistaken for a brand accent.
     ------------------------------------------------------------------------ */
  :focus-visible {
    outline: var(--focus-ring-width) solid var(--focus-ring);
    outline-offset: var(--focus-ring-width);
    border-radius: var(--radius-sm);
  }

  /* Never remove the outline without replacing it. This rule exists only to
     suppress the ring for mouse users on browsers that still fire :focus. */
  :focus:not(:focus-visible) {
    outline: none;
  }


  /* ------------------------------------------------------------------------
     SKIP LINK , keyboard users must be able to jump the nav
     ------------------------------------------------------------------------ */
  .skip-link {
    position: absolute;
    inset-block-start: var(--sp-2);
    inset-inline-start: var(--sp-2);
    z-index: var(--z-toast);
    padding: var(--sp-3) var(--sp-4);
    background-color: var(--btn-primary-bg);
    color: var(--btn-primary-fg);
    font-weight: var(--fw-semibold);
    border-radius: var(--radius-md);
    transform: translateY(-200%);
    transition: transform var(--dur-fast) var(--ease-out);
  }
  .skip-link:focus-visible {
    transform: translateY(0);
    text-decoration: none;
  }


  /* ------------------------------------------------------------------------
     FORM CONTROLS
     ------------------------------------------------------------------------ */
  input, textarea, select {
    background-color: var(--input-bg);
    color: var(--input-fg);
    border: var(--bw-hair) solid var(--input-border);
    border-radius: var(--radius-md);
    padding: var(--sp-3) var(--sp-4);
    width: 100%;
    min-height: var(--tap-min);
    transition: border-color var(--dur-fast) var(--ease-out),
                background-color var(--dur-fast) var(--ease-out);
  }
  input:hover, textarea:hover, select:hover {
    border-color: var(--color-border-strong);
  }
  input:focus, textarea:focus, select:focus {
    background-color: var(--input-bg-focus);
    border-color: var(--input-border-focus);
  }
  input::placeholder, textarea::placeholder {
    color: var(--input-placeholder);
    opacity: 1;                  /* Firefox dims placeholders by default */
  }
  input:disabled, textarea:disabled, select:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  /* iOS zooms the viewport when focusing an input under 16px. Forcing the
     base size on small screens prevents that jarring auto-zoom. */
  @media (max-width: 639px) {
    input, textarea, select {
      font-size: var(--fs-3);
    }
  }

  label {
    display: block;
    font-size: var(--fs-2);
    font-weight: var(--fw-medium);
    color: var(--color-text-secondary);
    margin-block-end: var(--sp-2);
  }


  /* ------------------------------------------------------------------------
     SCROLLBARS , themed, and now actually visible enough to grab
     ------------------------------------------------------------------------ */
  * {
    scrollbar-width: thin;
    scrollbar-color: var(--color-border-strong) transparent;
  }
  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb {
    background-color: var(--color-border-strong);
    border-radius: var(--radius-pill);
    border: 2px solid transparent;
    background-clip: content-box;
  }
  ::-webkit-scrollbar-thumb:hover {
    background-color: var(--color-text-muted);
  }


  /* ------------------------------------------------------------------------
     SELECTION
     ------------------------------------------------------------------------ */
  ::selection {
    background-color: var(--color-accent);
    color: var(--color-text-inverse);
  }


  /* ------------------------------------------------------------------------
     ICON PRIMITIVE , how every icon in this app is drawn
     ------------------------------------------------------------------------
     Icons are <svg class="icon"><use href="/static/icons/sprite.svg#i-name"/></svg>
     built by tools/build-icons.py from the LOCAL Font Awesome 6 sources.

     `fill: currentColor` is the whole trick: an icon is the same colour as
     the text next to it, automatically, in every theme, forever. That is
     what "embed the icons properly into the CSS" means in practice, and it
     is impossible with the emoji entities v1 used.

     1em sizing means an icon scales with its context's font-size. Override
     with --icon-size for the rare fixed case.
     ------------------------------------------------------------------------ */
  .icon {
    inline-size: var(--icon-size, 1em);
    block-size:  var(--icon-size, 1em);
    fill: currentColor;
    flex: none;                  /* never squash inside a flex row */
    vertical-align: -0.125em;    /* optically centre against the text baseline */
    pointer-events: none;        /* clicks belong to the parent control */
  }
  .icon--lg { --icon-size: 1.5rem; }
  .icon--xl { --icon-size: 2rem; }

  /* Spinner is the one icon that must move. Honours reduced-motion via the
     global override in tokens.css. */
  .icon--spin { animation: icon-spin 900ms linear infinite; }
  @keyframes icon-spin { to { transform: rotate(360deg); } }


  /* ------------------------------------------------------------------------
     SCREEN-READER-ONLY , for text that must exist but not be seen
     ------------------------------------------------------------------------ */
  .sr-only {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}
