/* ============================================================================
   ob_notify · ORBE

   ES  Hoja de estilos de la interfaz. Toca lo que quieras: no esta cifrada.
   EN  Interface stylesheet. Change whatever you like: it isn't encrypted.
   ========================================================================== */

/* ------------------------------------------------------------------ Fuentes
   ES  Van empaquetadas en web/fonts/, nunca desde internet: si el jugador va
       mal de red, la interfaz apareceria con la fuente del sistema.
       Se parten en latin y latin-ext para que el navegador solo descargue lo
       que necesita. Licencia SIL Open Font, textos junto a los archivos.
   EN  Bundled in web/fonts/, never fetched online: on a slow connection the
       interface would fall back to the system font.
       Split into latin and latin-ext so the browser only downloads what it
       needs. SIL Open Font licence, texts next to the files.

   ⚠️ format('woff2'), NOT format('woff2-variations'). The latter was never
      standardised and Chrome dropped it; a browser that doesn't know it will
      discard the whole @font-face and silently fall back. */

@font-face {
  font-family: 'Archivo';
  src: url('fonts/archivo-latin.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: block;
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'Archivo';
  src: url('fonts/archivo-latin-ext.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: block;
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('fonts/plexmono-500-latin.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: block;
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('fonts/plexmono-500-latin-ext.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: block;
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

:root {
  --bg:      #0A0B0D;
  --surface: #101216;
  --card:    #17191E;
  --line:    #24272E;

  --accent:  #E8B466;
  --ok:      #4FBF8B;
  --bad:     #E5574F;
  --warn:    #E8B466;
  --info:    #8E939C;

  --ink:   #EDEAE4;
  --ink-2: #9AA0AC;
  --ink-3: #62666F;

  --width: 380px;
  --speed: 200ms;
  --offset: 56px;

  /* ES  Sin rebote.  EN  No bounce. */
  --ease: cubic-bezier(.2, 0, 0, 1);
}

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  width: 100%; height: 100%;
  overflow: hidden;
  background: transparent;
  font-family: 'Archivo', system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  user-select: none;
  /* ES  La NUI ocupa la pantalla pero no captura clics: si lo hiciera, no
         podrias disparar mientras hay un aviso.
     EN  The NUI covers the screen but doesn't capture clicks: otherwise you
         couldn't shoot while a notification is up. */
  pointer-events: none;
}

svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* --------------------------------------------------------------- 1. La pila */

.stack {
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: var(--width);
  max-width: calc(100vw - 32px);
}

/* ES  Arriba en el centro tapa menos: el HUD de GTA vive en las esquinas.
   EN  Top centre covers less: GTA's HUD lives in the corners. */
.stack[data-pos='top-center']    { top: var(--offset); left: 50%; transform: translateX(-50%); }
.stack[data-pos='top-right']     { top: var(--offset); right: var(--offset); }
.stack[data-pos='top-left']      { top: var(--offset); left: var(--offset); }
.stack[data-pos='bottom-center'] { bottom: var(--offset); left: 50%; transform: translateX(-50%); flex-direction: column-reverse; }
.stack[data-pos='bottom-right']  { bottom: var(--offset); right: var(--offset); flex-direction: column-reverse; }
.stack[data-pos='bottom-left']   { bottom: var(--offset); left: var(--offset); flex-direction: column-reverse; }

/* ------------------------------------------------------------ 2. La tarjeta */

.note {
  position: relative;
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 12px 16px 12px 15px;
  border-radius: 12px;

  /* ⚠️ NO backdrop-filter.
     ES  En FiveM no desenfoca: pinta un rectangulo negro. El CEF no tiene
         acceso a la vista del juego, asi que no hay nada que muestrear.
         Lo que si funciona es el alfa normal, que es lo que se usa aqui.
     EN  In FiveM it doesn't blur: it paints a black rectangle. CEF has no
         access to the game view, so there is nothing to sample.
         Plain alpha does work, and that's what's used here. */
  background: linear-gradient(
    180deg,
    rgba(23, 26, 33, .86) 0%,
    rgba(11, 12, 16, .88) 100%
  );

  /* ES  Canto de luz arriba y linea fina alrededor: dan grosor al cristal.
     EN  Light edge on top plus a hairline: they give the glass thickness. */
  box-shadow:
    inset 0 1px 0 0 rgba(255, 255, 255, .16),
    inset 0 0 0 1px rgba(255, 255, 255, .08),
    0 12px 32px rgba(0, 0, 0, .55);

  overflow: hidden;
  pointer-events: auto;

  /* ES  Estado inicial. JS anade .is-in en el frame siguiente para animar.
     EN  Initial state. JS adds .is-in on the next frame to animate. */
  opacity: 0;
  transform: translateY(-14px) scale(.96);
  transition:
    opacity var(--speed) var(--ease),
    transform var(--speed) var(--ease);
}

.stack[data-pos^='bottom'] .note { transform: translateY(14px) scale(.96); }

.note.is-in { opacity: 1; transform: none; }

/* ES  Salida: se desvanece y se pliega, para que las de abajo suban solas.
   EN  Exit: fades out and collapses, so the ones below slide up on their own. */
.note.is-out {
  opacity: 0;
  transform: translateY(-8px) scale(.97);
  margin-top: calc(var(--h, 72px) * -1 - 10px);
  transition:
    opacity calc(var(--speed) * .8) var(--ease),
    transform calc(var(--speed) * .8) var(--ease),
    margin-top var(--speed) var(--ease);
}
.stack[data-pos^='bottom'] .note.is-out { margin-top: 0; margin-bottom: calc(var(--h, 72px) * -1 - 10px); }

/* ES  El color del estado vive solo en el icono. Placa y anillo no cambian.
   EN  The state colour lives only in the icon. Plate and ring never change. */
.note[data-type='success'] { --tone: #6FE0AE; }
.note[data-type='error']   { --tone: #FF7B74; }
.note[data-type='warning'] { --tone: var(--accent); }
.note[data-type='info']    { --tone: #A8AEBA; }
.note[data-type='neutral'] { --tone: var(--accent); }

/* ES  Al reemplazar por id: destello corto para que se note el cambio.
   EN  On replace-by-id: a short flash so the change is noticeable. */
.note.is-bumped { animation: bump 320ms var(--ease); }
@keyframes bump {
  0%   { transform: none; }
  35%  { transform: scale(1.018); }
  100% { transform: none; }
}

/* -------------------------------------------------- 3. Icono y anillo */

/* ES  Icono suelto. Lo unico que lo rodea es la O de ORBE.
   EN  Bare icon. The only thing around it is the ORBE O. */
.note__lead {
  position: relative;
  width: 44px; height: 44px;
  flex: none;
  display: grid;
  place-items: center;
}

.note__icon {
  width: 18px; height: 18px;
  color: var(--tone, var(--ink-2));
  z-index: 1;
}

/* ES  LA O DE ORBE. No es un circulo de progreso: son los dos arcos del
       isotipo, creciendo en espejo desde el hueco de arriba. Cuando el aviso
       termina, la O esta cerrada. Siempre en blanco.
   EN  THE ORBE O. Not a progress circle: the logo's two arcs, growing in
       mirror from the top gap. When the notification ends, the O is closed.
       Always white. */
.note__ring {
  position: absolute;
  inset: 0;
  width: 44px; height: 44px;
}

.note__ring path {
  fill: none;
  stroke-linecap: butt;   /* ES cortes rectos · EN straight cuts */
  stroke-width: 5;
}

.note__ring-track { stroke: rgba(255, 255, 255, .11); }

.note__ring-fill {
  stroke: #FFFFFF;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;   /* ES empieza vacio · EN starts empty */
  transition: stroke-dashoffset linear;
}

.note:not(.has-ring) .note__ring { display: none; }
/* ES  Sin anillo el icono necesita menos sitio.  EN  Without the ring the icon needs less room. */
.note:not(.has-ring) .note__lead { width: 26px; height: 26px; }

/* ------------------------------------------------------------- 4. El texto */

.note__body { flex: 1; min-width: 0; }

/* ES  Cabecera opcional. Mono, mayusculas, en el color del estado.
   EN  Optional eyebrow. Mono, uppercase, in the state colour. */
.note__eyebrow {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--tone, var(--ink-3));
  line-height: 1;
  margin-bottom: 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.note:not(.has-eyebrow) .note__eyebrow { display: none; }

.note__title {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -.01em;
  line-height: 1.3;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.note__desc {
  font-size: 13px;
  line-height: 1.4;
  color: #A4AAB6;
  margin-top: 3px;
  overflow-wrap: anywhere;
}

/* ES  La placa es translucida: detras puede haber un cielo blanco.
   EN  The plate is translucent: there may be a white sky behind it. */
.note__title, .note__desc, .textui__text {
  text-shadow: 0 1px 2px rgba(0, 0, 0, .55);
}

/* ES  Lo que envuelvas en `acentos graves` sale en mono: matriculas, precios.
   EN  Anything wrapped in `backticks` renders in mono: plates, prices. */
.note__desc code, .note__title code {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: .92em;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

/* ES  Barra lineal opcional, alternativa al anillo.
   EN  Optional linear bar, an alternative to the ring. */
.note__bar {
  position: absolute;
  left: 0; bottom: 0;
  height: 2px;
  width: 100%;
  transform-origin: left;
  background: var(--tone, var(--ink-3));
  opacity: .5;
  transform: scaleX(1);
  transition: transform linear;
}
.note:not(.has-bar) .note__bar { display: none; }

/* ------------------------------------------------------ 5. Cola desbordada */

.overflow {
  align-self: center;
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 5px 10px;
  opacity: 0;
  transition: opacity var(--speed) var(--ease);
}
.overflow.is-in { opacity: 1; }

/* ---------------------------------------------------------------- 6. TextUI */

.textui {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 16px 10px 15px;
  border-radius: 10px;
  max-width: 420px;

  /* ES  Mismo cristal que la tarjeta.   EN  Same glass as the card. */
  background: linear-gradient(
    180deg,
    rgba(23, 26, 33, .86) 0%,
    rgba(11, 12, 16, .88) 100%
  );
  box-shadow:
    inset 0 1px 0 0 rgba(255, 255, 255, .16),
    inset 0 0 0 1px rgba(255, 255, 255, .08),
    0 10px 26px rgba(0, 0, 0, .5);

  opacity: 0;
  visibility: hidden;
  transform: translateY(6px) scale(.97);
  transition:
    opacity var(--speed) var(--ease),
    transform var(--speed) var(--ease),
    visibility 0s linear var(--speed);
}
.textui.is-open {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

.textui[data-pos='right']  { right: var(--tui-offset, 48px); top: 50%; margin-top: -22px; }
.textui[data-pos='left']   { left: var(--tui-offset, 48px);  top: 50%; margin-top: -22px; }
.textui[data-pos='top']    { top: var(--tui-offset, 48px);    left: 50%; transform: translateX(-50%) translateY(6px) scale(.97); }
.textui[data-pos='bottom'] { bottom: var(--tui-offset, 48px); left: 50%; transform: translateX(-50%) translateY(6px) scale(.97); }
.textui[data-pos='top'].is-open,
.textui[data-pos='bottom'].is-open { transform: translateX(-50%); }

/* ES  El color vive en el icono, igual que en la tarjeta.
   EN  The colour lives in the icon, same as the card. */
.textui[data-type='success'] { --tui-tone: #6FE0AE; }
.textui[data-type='error']   { --tui-tone: #FF7B74; }
.textui[data-type='warning'] { --tui-tone: var(--accent); }
.textui[data-type='info']    { --tui-tone: #A8AEBA; }

.textui__icon {
  width: 16px; height: 16px;
  flex: none;
  color: var(--tui-tone, var(--accent));
}

/* ES  Flex, no texto corrido: es la unica forma de que la placa de la tecla
       quede centrada de verdad con las palabras de al lado.
   EN  Flex, not inline text: the only way the key chip lines up properly
       with the words next to it. */
.textui__text {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
  color: var(--ink);
  white-space: nowrap;
}

.textui__seg { display: inline-block; }

/* ES  La tecla: mono, placa mas clara y canto inferior que le da grosor.
   EN  The key: mono, lighter plate and a bottom edge that gives it depth. */
.textui__key {
  display: inline-grid;
  place-items: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  margin: 0 3px;
  border-radius: 6px;
  background: rgba(255, 255, 255, .1);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .16),
    0 2px 0 0 rgba(0, 0, 0, .5);
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink);
  flex: none;
  transition: transform 90ms var(--ease), box-shadow 90ms var(--ease),
              background 90ms var(--ease), color 90ms var(--ease);
}

/* ES  Al pulsar baja 2 px y pierde el canto.
   EN  On press it drops 2 px and loses its edge. */
.textui.is-pressed .textui__key {
  transform: translateY(2px);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .16),
    0 0 0 0 rgba(0, 0, 0, .5);
  background: var(--accent);
  color: var(--bg);
}

/* --------------------------------------------------------------- 7. Respeto */

@media (prefers-reduced-motion: reduce) {
  .note, .note.is-out, .textui, .overflow {
    transition-duration: .01ms !important;
  }
  .note.is-bumped { animation: none; }
}
