/* ============================================================
   updates.css -- UPDATES (GHOST OS native app)
   ------------------------------------------------------------
   App sheet for mountUpdatesApp() in js/desktop.js. Own file,
   upd-* prefix, THEME VARIABLES ONLY -- never --nos-*. desktop.css
   remaps the legacy names (--fg, --cyan, --border, --bg-soft, ...)
   onto the OS palette on body.null-os .nos-win-body, so a sheet
   written this way re-themes with the player's own THEME app
   instead of fighting it. The --nos-* tokens are GHOST's own
   chrome and do not belong here. Never append this to desktop.css.

   NO HARDCODED COLOURS. Translucent accents are done with an
   opacity layer rather than rgba(), because the rgb component
   tokens are not remapped into the window body -- and color-mix()
   is younger than some of the Android WebViews this ships to.

   SCALING: the panel sizes its own hero off ITS OWN width via a
   container query. A GHOST window is a box inside the page, so vw
   says nothing useful about it. Engines without container queries
   keep the px values that precede each cq rule: the old fixed look,
   degraded, never broken.

   TOUCH: this runs fullscreen on a phone in portrait. Every button
   is >= 40px tall, and under 380px the row action drops below its
   text instead of squeezing it.
   ============================================================ */

.upd-app {
  height: 100%;
  overflow: hidden;
  container-type: inline-size;
  container-name: updapp;
  font-family: var(--font-mono, monospace);
}

.upd-scroll {
  height: 100%;
  overflow-y: auto;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* ============================================================
   HERO -- the one line that answers "am I current"
   ============================================================ */
.upd-hero {
  display: flex;
  align-items: center;
  gap: 13px;
  padding-bottom: 13px;
  border-bottom: 1px solid var(--border);
}

/* The glyph sits on a tinted disc so it reads as an app mark rather
   than a stray icon. The disc is a pseudo-element at low opacity --
   see the no-hardcoded-colours note above. */
.upd-glyph {
  position: relative;
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--cyan);
}
.upd-glyph::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.1;
}
.upd-glyph::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid currentColor;
  opacity: 0.35;
}
.upd-glyph svg {
  position: relative;
  width: 54%;
  height: 54%;
}

.upd-head { min-width: 0; }

.upd-status {
  font-size: 15px;
  letter-spacing: 0.4px;
  color: var(--fg);
  line-height: 1.25;
}
.upd-sub {
  margin-top: 4px;
  font-size: 11px;
  color: var(--fg-dim);
}

/* State lives on the app root so the glyph and the headline always
   agree -- one class to set, no chance of a cyan glyph over a red
   headline. */
.upd-app.is-ok    .upd-status { color: var(--fg-bright); }
.upd-app.is-new   .upd-status { color: var(--cyan); }
.upd-app.is-warn  .upd-status { color: var(--amber); }
.upd-app.is-busy  .upd-status { color: var(--fg-dim); }
.upd-app.is-warn  .upd-glyph  { color: var(--amber); }
.upd-app.is-busy  .upd-glyph  { color: var(--fg-dim); }

/* Something is actually available: breathe, slowly, once every two
   seconds. Enough to catch the eye on open, not enough to nag. */
.upd-app.is-new .upd-glyph::after { animation: upd-ring 2.4s ease-out infinite; }
@keyframes upd-ring {
  0%   { transform: scale(1);    opacity: 0.35; }
  60%  { transform: scale(1.18); opacity: 0;    }
  100% { transform: scale(1.18); opacity: 0;    }
}

/* While a check runs the glyph sweeps instead of sitting dead. */
.upd-app.is-busy .upd-glyph svg { animation: upd-pulse 1.1s ease-in-out infinite; }
@keyframes upd-pulse {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}

/* ============================================================
   PROGRESS -- only on screen while a bundle downloads
   ============================================================ */
.upd-bar {
  display: none;
  position: relative;
  height: 4px;
  border-radius: 2px;
  overflow: hidden;
  background: var(--bg-soft);
}
.upd-bar.is-on { display: block; }
.upd-bar > i {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--cyan);
  transition: width 0.25s ease-out;
}

/* ============================================================
   ROWS -- one per update source
   ============================================================ */
.upd-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.upd-row {
  position: relative;
  display: flex;
  /* top, not centre: the dot belongs beside the LABEL, and a two-line detail
     would otherwise drag it down to the middle of the card. */
  align-items: flex-start;
  gap: 11px;
  padding: 11px 12px 11px 13px;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--r-sm, 3px);
  overflow: hidden;
}
/* Left accent bar: the row's state, readable before any text is. */
.upd-row::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--fg-faint);
}
.upd-row.is-ok::before   { background: var(--cyan); opacity: 0.45; }
.upd-row.is-new::before  { background: var(--cyan); }
.upd-row.is-warn::before { background: var(--amber); }
.upd-row.is-info::before { background: var(--fg-dim); }

/* A row with something to collect is lifted out of the list. */
.upd-row.is-new {
  border-color: var(--border-bright);
  background: var(--bg-elev);
}

/* The source mark: store / watch / system. It says WHAT the row is about;
   its colour (and the accent bar) say whether it needs you. Aligned to the
   label, not the card, so a two-line detail cannot drag it to the middle. */
.upd-ico {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin-top: -1px;
  display: block;
  color: var(--fg-faint);
}
.upd-ico svg { width: 100%; height: 100%; display: block; }
.upd-row.is-ok   .upd-ico { color: var(--cyan); opacity: 0.6; }
.upd-row.is-new  .upd-ico { color: var(--cyan); }
.upd-row.is-warn .upd-ico { color: var(--amber); }
.upd-row.is-info .upd-ico { color: var(--fg-dim); }

/* basis 0, not auto: with auto the browser sizes the wrap decision off the
   text's CONTENT width, so a two-line detail pushes the dot onto a line of
   its own in the narrow layout. min-width:0 alone does not prevent that --
   it governs shrinking, not the hypothetical size wrapping is judged by. */
.upd-text { flex: 1 1 0%; min-width: 0; }

.upd-label {
  font-size: 11px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--fg);
}
.upd-row.is-new .upd-label { color: var(--fg-bright); }

.upd-detail {
  margin-top: 3px;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--fg-dim);
  overflow-wrap: anywhere;
}

/* ============================================================
   BUTTONS
   ============================================================ */
.upd-act,
.upd-check {
  position: relative;
  flex: 0 0 auto;
  align-self: center;
  font-family: inherit;
  font-size: 10.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--cyan);
  background: transparent;
  border: 1px solid var(--cyan);
  border-radius: var(--r-sm, 3px);
  min-height: 40px;
  padding: 0 14px;
  cursor: pointer;
  /* The fill is a layer, not a colour, so it tracks the theme. */
  isolation: isolate;
}
.upd-act::before,
.upd-check::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: currentColor;
  opacity: 0.08;
  transition: opacity 0.15s;
}
.upd-act:hover::before,
.upd-check:hover::before { opacity: 0.16; }
.upd-act:active,
.upd-check:active { transform: translateY(1px); }

/* A disabled check button stops looking like an accent at all, so the
   cooldown reads as "not now" rather than "broken". */
.upd-check:disabled {
  color: var(--fg-dim);
  border-color: var(--border);
  cursor: default;
  transform: none;
}
.upd-check:disabled::before { opacity: 0; }

.upd-foot {
  display: flex;
  align-items: center;
  gap: 11px;
  flex-wrap: wrap;
}
.upd-check { padding: 0 18px; }
.upd-note {
  font-size: 11px;
  color: var(--fg-dim);
}
.upd-note.is-warn { color: var(--amber); }

.upd-empty {
  font-size: 11.5px;
  color: var(--fg-dim);
  padding: 8px 2px;
}

/* ============================================================
   META -- build identity, deliberately quiet, pinned to the bottom
   ============================================================ */
.upd-meta {
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 10px;
  line-height: 1.7;
  color: var(--fg-dim);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ============================================================
   CONTAINER QUERIES -- size against the WINDOW, not the viewport
   ============================================================ */
@container updapp (min-width: 0px) {
  .upd-glyph {
    /* ~9% of the panel: floored so a narrow window keeps it legible,
       capped so a maximized one does not get a billboard. */
    width: clamp(34px, 9cqw, 60px);
    height: auto;
    aspect-ratio: 1 / 1;
  }
  .upd-status { font-size: clamp(14px, 3.2cqw, 21px); }
  .upd-sub    { font-size: clamp(11px, 1.9cqw, 13px); }
  .upd-hero   { gap: clamp(12px, 2.5cqw, 20px); }
  .upd-scroll { padding: clamp(12px, 3cqw, 22px); }
}

/* Narrow window (a phone in portrait, or a small floating window):
   the action drops under its text rather than crushing the detail
   line into a two-word column. */
@container updapp (max-width: 380px) {
  .upd-row {
    flex-wrap: wrap;
    row-gap: 9px;
  }
  /* The dot stays beside its label -- it is that row's status, not a
     bullet. Only the action wraps, and it takes the full width so it is
     an easy thumb target rather than a sliver in the corner. */
  .upd-act {
    flex: 1 1 100%;
    margin-left: 18px;
  }
}

/* A very wide window would otherwise stretch one-line rows across a
   whole monitor. Cap the column and centre it, like a real settings
   pane. */
@container updapp (min-width: 760px) {
  .upd-scroll > * { max-width: 680px; width: 100%; margin-left: auto; margin-right: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .upd-app.is-new .upd-glyph::after,
  .upd-app.is-busy .upd-glyph svg { animation: none; }
  .upd-bar > i { transition: none; }
}
