/* ============================================================================
   The OxOnOS site — the components getoxon.com does not have.

   ⛔ READ THIS BEFORE ADDING A RULE HERE. `tokens.css` and `site.css` in this
   folder are VERBATIM COPIES of the ones in `../../site/assets/css/`, because
   the two sites deploy to two different buckets and cannot share a file. Every
   class those two files already define — .sect .wrap .band-dark .band-deep
   .act-head .sub-head .display .lead .muted .label .lines .claim .gloss .plate
   .grid .cell .pivot .rv .btn .figure .rows .row .pill .colophon .legal — is
   used here as-is and must NOT be redefined. This file is only for what is
   genuinely new, and everything in it is new because it is about an operating
   system rather than about a machine.

   ⚠️ The copies will drift. When `site.css` changes meaningfully over there,
   copy it over; `site-oxonos/README.md` says the same thing where somebody
   will actually read it.
   ========================================================================= */

/* ── THE RAIL ────────────────────────────────────────────────────────────────
   ⭐ THE IDEA OF THIS SITE, AND THE ONE COMPONENT THAT EARNS ITS KEEP: the
   visitor meets the operating system through the operating system's own
   furniture. Nine entries, in the OS's own order, with the OS's own icons —
   lifted path-for-path from ~/om-oxonos/ui/index.html so the replica cannot
   drift into an illustration OF a rail.

   ⛔ IT IS NOT A TAB WIDGET DRESSED UP. The entries are the nine real rail
   entries and nothing else. Do not add a tenth for "Fleet" or "People": the OS
   deliberately keeps both OUT of its rail (a box with one computer and nobody
   on the network is COMPLETE, and a rail entry would put them on the ordinary
   path). This page honours that by giving each of them its own act further
   down, which is the structure telling the truth about the product.          */

.railshow {
  display: grid;
  grid-template-columns: 13.5rem minmax(0, 1fr);
  border-top: var(--hair) solid var(--paper-edge);
  border-bottom: var(--hair) solid var(--paper-edge);
}

.railshow-rail {
  display: flex; flex-direction: column;
  border-right: var(--hair) solid var(--paper-edge);
  padding: clamp(1rem, 2vw, 1.6rem) 0;
  gap: 1px;
}

.railshow-rail button {
  display: flex; align-items: center; gap: 0.7em;
  font: inherit; font-size: var(--t-small);
  text-align: left; width: 100%;
  padding: 0.6em 1em 0.6em 0;
  background: none; border: 0; border-radius: var(--radius);
  color: var(--ink-soft); cursor: pointer;
  transition: color 120ms var(--ease), background 120ms var(--ease);
}
.railshow-rail button svg { flex: 0 0 auto; opacity: 0.7; }
.railshow-rail button:hover { color: var(--ink); }
.railshow-rail button[aria-selected="true"] {
  color: var(--ink); background: var(--paper-raise);
  box-shadow: inset 0 0 0 var(--hair) var(--paper-edge);
  padding-left: 1em;
}
.railshow-rail button[aria-selected="true"] svg { opacity: 1; }
.railshow-rail button:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.railshow-stage { padding: clamp(1.4rem, 3vw, 2.4rem) 0 clamp(1.4rem, 3vw, 2.4rem) clamp(1.4rem, 3vw, 2.6rem); }

/* ⛔ EVERY PANEL IS IN THE DOM AND VISIBLE BY DEFAULT. The same rule as the
   reveal on the other site: content is readable with no JavaScript at all, and
   only becomes hide-able once the script has confirmed it can show it again.
   `html.rs-live` is set by the script. A visitor with JS off gets nine screens
   stacked down the page, which is a worse page and a complete one. */
.rs-live .rs-panel { display: none; }
.rs-live .rs-panel.on { display: block; }
.rs-panel + .rs-panel { margin-top: clamp(2rem, 4vw, 3rem); }

/* ⛔ THE PICTURE GETS THE WHOLE STAGE, AND IT TOOK A LOOK TO SEE WHY IT HAD TO.
   The first build of this put the copy in a column beside the screenshot, which
   left the screenshot about 515 px wide inside a 1240 px page — a picture OF a
   screen rather than a screen anybody could read. On a site whose entire
   argument is "look at what it says about itself", a screenshot you have to
   squint at is the one thing that cannot be allowed. The copy went underneath,
   in the same two-column shape .sub-head uses everywhere else on both sites. */
.rs-fig { margin: 0; }
.rs-fig img {
  display: block; width: 100%; height: auto;
  border: var(--hair) solid var(--paper-edge);
  border-radius: var(--radius);
  background: var(--paper-raise);
}

.rs-say {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  gap: clamp(0.8rem, 2.5vw, 2.4rem);
  align-items: start;
  margin-top: clamp(1.2rem, 2.5vw, 1.8rem);
}
.rs-say h3 { margin: 0.45rem 0 0.6rem; max-width: 20ch; }
.rs-say p { font-size: var(--t-small); color: var(--ink-soft); }
.rs-say p + p { margin-top: 0.7rem; }
.rs-say .gloss { display: block; text-align: left; margin-top: 0.9rem; }

@media (max-width: 900px) { .rs-say { grid-template-columns: minmax(0, 1fr); } }

@media (max-width: 760px) {
  /* The OS collapses its own rail to icons at 760. This collapses it to a
     scrolling strip instead, because a website visitor has not learned what
     the icons mean and a row of nine unlabelled glyphs is a puzzle. */
  .railshow { grid-template-columns: minmax(0, 1fr); }
  .railshow-rail {
    flex-direction: row; overflow-x: auto; gap: 0.4rem;
    border-right: 0; border-bottom: var(--hair) solid var(--paper-edge);
    padding: 0.9rem 0;
    scrollbar-width: none;
  }
  .railshow-rail::-webkit-scrollbar { display: none; }
  .railshow-rail button { width: auto; white-space: nowrap; padding: 0.5em 0.85em; }
  .railshow-rail button[aria-selected="true"] { padding-left: 0.85em; }
  .railshow-stage { padding: clamp(1.2rem, 3vw, 2rem) 0; }
}

/* ── A TILE, QUOTED ──────────────────────────────────────────────────────────
   The OS reports itself in tiles: a label, a state, a value, and a sentence
   underneath that says how it knows. Three of them are quoted on this page as
   TYPE rather than as a screenshot, because they are the argument and a reader
   should be able to select the words.
   ⛔ Every word inside one of these is the PRODUCT'S, not ours. If a sentence
   in one of these is not in `~/om-oxonos/ui/js/screens/`, it does not belong
   in a .ostile — put it in ordinary body copy where it is plainly us talking. */

.ostile {
  padding: clamp(1.2rem, 1rem + 1vw, 1.7rem) clamp(1rem, 2vw, 1.5rem);
  background: var(--paper-raise);
  border: var(--hair) solid var(--paper-edge);
  border-radius: var(--radius);
  display: flex; flex-direction: column; gap: 0.5rem;
  min-width: 0;
}
.ostile-h { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.ostile-v {
  font-size: clamp(1.3rem, 1.1rem + 0.8vw, 1.8rem); font-weight: 300;
  letter-spacing: -0.015em; line-height: 1.1; margin: 0;
  font-variant-numeric: tabular-nums;
}
.ostile p { font-size: var(--t-small); color: var(--ink-soft); margin: 0; }
.ostile .state { align-self: flex-start; }
.ostiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(0.8rem, 1.5vw, 1.2rem); }
@media (max-width: 860px) { .ostiles { grid-template-columns: minmax(0, 1fr); } }

/* ── THE UPDATE SET PIECE ────────────────────────────────────────────────────
   ⭐ The one behaviour of this operating system that nothing else on the
   reader's desk has: it will not tell you it is up to date, because it never
   asked anybody. Pressing the button gets the product's own sentence back.

   ⛔ IT MUST NOT GROW INTO A FAKE PRODUCT DEMO. Two presses, two sentences,
   both of them the machine's own words, and it stops. The moment this invents
   a dialogue the box does not have, it becomes a claim stronger than the code
   and the best thing on the page turns into the worst.                       */

.upd {
  border: var(--hair) solid var(--dark-edge);
  border-radius: var(--radius);
  background: var(--dark-panel);
  padding: clamp(1.3rem, 1rem + 1.6vw, 2.2rem);
  max-width: 62ch;
}
.upd .btn { margin-bottom: 0.2rem; }
.upd-out {
  display: block; margin-top: 1.1rem;
  font-size: var(--t-small); line-height: var(--lh-body);
  color: var(--on-dark-soft); min-height: 1.5em;
}
.upd-out strong { color: var(--on-dark); font-weight: 400; }
.upd-out .say { display: block; }
.upd-out .say + .say { margin-top: 0.8rem; padding-top: 0.8rem; border-top: var(--hair) solid var(--dark-edge); }
.upd-next { margin-top: 1.1rem; }
.upd-next[hidden] { display: none; }

/* ── A QUOTE FROM THE MACHINE ────────────────────────────────────────────────
   Used once, for the row on the System screen that this whole site is named
   after. It is set in the mono face on purpose: these are not our words. */
.osquote {
  margin: clamp(1.6rem, 3vw, 2.4rem) 0 0;
  padding-left: clamp(1rem, 2vw, 1.6rem);
  border-left: 2px solid var(--alu);
  max-width: 62ch;
}
.osquote p {
  font-family: var(--font-mono);
  font-size: var(--t-small);
  line-height: 1.7;
  color: var(--ink);
}
/* ⛔ `.band-deep` IS A LIGHT BAND. It is paper-deep — a slightly deeper cream —
   and only `.band-dark` is actually dark. This rule originally listed both, and
   the quote rendered in near-white on cream: present in the DOM, invisible on
   the page, and it was the most important sentence in the section. A class
   named "deep" is not a class named "dark". */
.band-dark .osquote p { color: var(--on-dark); }
.osquote cite { display: block; margin-top: 0.7rem; font-style: normal; }

/* ── The figure caption used under the two exclusive screens ──────────────── */
.oscap { display: flex; flex-wrap: wrap; gap: 0.4rem 1.6rem; margin-top: 0.8rem; }

/* ── Hero overrides ──────────────────────────────────────────────────────────
   ⛔ `.hero-fig` on getoxon.com carries a large NEGATIVE right margin so the
   Ox1 render bleeds off the edge of the page. That is right for a photograph
   of an object and wrong for a trademark: it cropped the emblem the first time
   this page was looked at. The bleed is cancelled here rather than in the
   shared stylesheet, which must stay byte-identical to the one it is copied
   from or the copies become a merge problem instead of a copy. */
.hero-mark { margin-right: 0; display: grid; place-items: center; }
.hero-mark img {
  width: auto; margin: 0;
  height: clamp(180px, 26vw, 340px);
  max-height: none; max-width: 100%;
}
@media (max-width: 820px) {
  .hero-mark { margin-inline: 0; order: 2; }
  .hero-mark img { width: auto; height: clamp(140px, 30vw, 220px); }
}

/* ⛔ A SPENT BUTTON MUST READ AS FINISHED, NOT AS BROKEN. site.css dims any
   disabled button to 45 % opacity, which is right on paper and wrong on the
   dark panel: the second button's label went to near-invisible grey on near
   black, and the only way to find that out was to press it and look. These two
   buttons are the one interaction on the page, so the state they spend most of
   their life in is the one that has to be legible. */
.upd .btn:disabled {
  opacity: 1; cursor: default;
  background: transparent;
  color: var(--on-dark-soft);
  border: var(--hair) solid var(--dark-edge);
}
.upd .btn-ghost:disabled { color: var(--on-dark-faint); }
