/* NA Vision — base.
 *
 * Rescued from the rabIT shop-notes stylesheet, which was carrying three things
 * the HUD cannot live without: the box-sizing reset, the design tokens, and the
 * body ground itself. Dropping that sheet wholesale left a white page with no
 * reset — this is the part that had to come along, rescoped from
 * `body.shop-notes` to `body.os`.
 */

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

html:has(body.os) {
  height: 100%;
}

body.os {
  --sn-black: #000;
  --sn-text: #f2f2f2;
  --sn-text-2: #b5b5b5;
  --sn-text-3: #7a7a7a;
  --sn-line: rgba(255, 255, 255, 0.14);
  --sn-line-strong: rgba(255, 255, 255, 0.28);
  --sn-input: rgba(0, 0, 0, 0.48);
  --sn-warn: #d4d4d4;
  --sn-chip-radius: 4px;
  --sn-chip-bg: rgba(255, 255, 255, 0.07);
  --sn-chip-border: rgba(255, 255, 255, 0.20);
  --sn-chip-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
  --sn-tile-radius: 18px;
  --sn-tile-gap: 18px;
  --sans: "Inter", system-ui, "Noto Sans CJK SC", "Noto Sans Devanagari", sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "Noto Sans CJK SC", "Noto Sans Devanagari", monospace;
  margin: 0;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  padding-top: calc(env(safe-area-inset-top, 0px) + 56px);
  background: var(--sn-black);
  color: var(--sn-text);
  font-family: var(--sans);
  font-size: 13px;
  -webkit-font-smoothing: antialiased;
}

@media (max-width: 860px) {
  html:has(body.os),
  body.os {
    height: auto;
    min-height: 100dvh;
    overflow-x: hidden;
    overflow-y: auto;
  }
}

/* The mark doubles as the hamburger trigger. Showing another product's wordmark
   on a school launcher is worse than showing none, so doors.js sets
   .no-wordmark whenever the tenant supplies no wordmark of its own. The hook
   used to be the rabIT filename in the src; it is a class now, and the element
   ships a transparent pixel. */
.no-wordmark .hub-wordmark {
  display: none;
}

/* The two lid discs are positioned as percentages of the rabbit silhouette's
   eyes. Any other mark puts them somewhere arbitrary, so a tenant that supplies
   no lid_offsets gets no blink at all. */
.no-lids .os-mark__lid {
  display: none;
}

/* Tenant accent replaces the rabIT lime.
   .os-meta declares its colour twice — hex, then color(srgb ...) — because
   wide-gamut Chrome washes the hex out through the goo filter. One override at
   higher specificity beats both. --os-lime is an RGB triplet, not a colour, so
   doors.js supplies it separately. */
body.os .os-meta {
  /* !important is load-bearing here and is the only one in this project.
     os2Orb paints the metaball's colour as an INLINE style at runtime
     (background: color(srgb ...)), so no ordinary author rule can reach it.
     An author !important outranks a non-important inline style, which lets the
     tenant accent win without editing the orb. */
  background: var(--na-accent, #c2ffa8) !important;
}

body.os {
  --os-lime: var(--na-accent-rgb, 194, 255, 168);
}

/* ---------------------------------------------------------------------------
   North Allegheny palette.

   Values arrive from the tenant manifest as --na-* custom properties; the
   fallbacks below are the district's published values so the very first paint
   is already branded rather than rabIT grey-green.
   --------------------------------------------------------------------------- */
body.os {
  --sn-black: var(--na-black, #000000);
  --sn-text: var(--na-white, #ffffff);
  --sn-text-2: var(--na-gray-light, #cccccc);
  --sn-text-3: var(--na-gray-dark, #5e5e5e);
}

/* The orb paints each corner mass's fill inline, same as the metaball, so this
   needs !important to reach it. The centre mass is excluded deliberately: it
   must stay transparent or the metaball stops welding into one blob. */
body.os .os-mass:not(.os-mass--center) {
  background: var(--na-white, #ffffff) !important;
}

/* Door glyphs sit on light gray, so they take NA black rather than the old
   near-black #231f20. */
body.os .os-door__icon {
  color: var(--na-black, #000000);
}

/* Vendor marks are raster, so the sheet's `.os-door__icon svg` sizing rule does
   not reach them. Contain rather than cover — these are logos with their own
   padding and cropping them would be wrong. The radius is what turns a square
   logo into something that reads as an app tile. */
body.os .os-door__icon img.os-door__glyph {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* No radius and no crop. These are the vendors' marks: rounding the corners
     clipped the Renaissance wordmark, and reshaping someone's logo is the thing
     every brand guide tells you not to do. Let each one be its own shape. */
}

/* The district mark is the hamburger, top centre.

   .rabit-corner already pins this chrome top-centre, so only the image and its
   size change here. The menu builds its <img> after doors.js has run, so the
   swap is `content:` on the element rather than a node lookup — order-independent,
   and it keeps the manifest in charge of which mark appears. When no wordmark is
   declared, --na-wordmark is unset, `content` falls back to the original image,
   and .no-wordmark hides it instead.

   Sized deliberately below the centre paw (min(68px, 13vmin)) and well below the
   corner masses: this is chrome, not one of the four things you came here to tap. */
body.os .hub-wordmark {
  content: var(--na-wordmark);
  width: min(84px, 14vmin);
  height: auto;
  object-fit: contain;
}

/* ---------------------------------------------------------------------------
   The paw IS the ball.

   markFollow.js mirrors the centre mass's inline left/top/transform/width onto
   the mark every frame, so the paw inherits the whole physics — follow, flick,
   wall bounce, squash, the merge into a corner — without the orb being touched.

   The four .os-meta circles that used to draw the gold blob are hidden: they sit
   inside #lava-goo, and leaving them on would put a gold disc behind a gold paw.
   The trade is the centre's share of the liquid weld during a merge; the corner
   masses still goo against each other.

   mix-blend-mode goes back to normal — `screen` was there to lift a white
   silhouette off black, and it would blow the paw out to white the moment it
   crossed one of the white corner blobs.
   --------------------------------------------------------------------------- */
/* Kiss and colour bleed, with the paw on top.

   Masking the mass to the paw did work — the shape is there with the filter
   off — but #lava-goo blurs by 16px and then re-thresholds the alpha, and the
   paw's toe gaps are about 5px at this size. They close. Surviving that blur
   would need a paw roughly 400px across, which is not what the centre is.

   So the metaball goes back to being a metaball: it welds, kisses and bleeds
   into the corners exactly as designed, inside the filter. The paw rides on top
   of it, outside the filter, sharp — in the district's black, which reads on
   gold and does not fight it.

   markFollow.js keeps the two locked together, insetting the paw so it sits
   inside the ball rather than covering it. */
body.os .os-mark {
  mix-blend-mode: normal;
  z-index: 3;
}

/* ---------------------------------------------------------------------------
   Sign-in gate.

   Shown once per browser, before the doors are used. It exists because BrainPOP
   cannot mint a launch token without an existing session, and because a warm
   session makes the other three land instantly instead of detouring through a
   login form.

   It is skippable on purpose: a student who is already signed in should not be
   made to click through a screen telling them to sign in.
   --------------------------------------------------------------------------- */
.tv-gate {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: grid;
  place-items: center;
  padding: 24px;
  background: color-mix(in srgb, var(--na-black, #000) 88%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.tv-gate__card {
  width: min(420px, 100%);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.tv-gate__mark {
  width: 64px;
  height: auto;
  /* the black paw needs lifting off the black ground here */
  filter: brightness(0) saturate(100%) invert(72%) sepia(58%)
          saturate(1400%) hue-rotate(357deg) brightness(101%) contrast(97%);
}

.tv-gate__title {
  margin: 0;
  font-family: var(--sans);
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--na-white, #fff);
}

.tv-gate__body {
  margin: 0;
  max-width: 34ch;
  font-family: var(--sans);
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--na-gray-light, #ccc);
}

.tv-gate__row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin-top: 4px;
}

.tv-gate__btn {
  font-family: var(--sans);
  /* the shell's button styles lowercase everything; this copy is written */
  text-transform: none;
  font-size: 15px;
  font-weight: 600;
  color: var(--na-black, #000);
  background: var(--na-gold, #fcb612);
  border: 2px solid var(--na-gold, #fcb612);
  border-radius: 999px;
  padding: 11px 22px;
  cursor: pointer;
  min-height: 44px;
}

.tv-gate__btn--ghost {
  color: var(--na-gold, #fcb612);
  background: transparent;
}

.tv-gate__btn:focus-visible,
.tv-gate__skip:focus-visible {
  outline: 2px solid var(--na-white, #fff);
  outline-offset: 3px;
}

.tv-gate__skip {
  font-family: var(--sans);
  text-transform: none;
  font-size: 13px;
  color: var(--na-gray-dark, #5e5e5e);
  background: none;
  border: 0;
  padding: 8px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.tv-gate__skip:hover {
  color: var(--na-gray-light, #ccc);
}

@media (prefers-reduced-motion: reduce) {
  .tv-gate { backdrop-filter: none; -webkit-backdrop-filter: none; }
}

.tv-qr {
  position: fixed;
  inset: 0;
  z-index: 2010;
  display: grid;
  place-items: center;
  padding: 24px;
  background: color-mix(in srgb, var(--na-black, #000) 88%, transparent);
}

.tv-qr__card {
  width: min(420px, 100%);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.tv-qr__title {
  margin: 0;
  font-family: var(--sans);
  font-size: 22px;
  font-weight: 700;
  color: var(--na-white, #fff);
}

.tv-qr__body {
  margin: 0;
  max-width: 34ch;
  font-family: var(--sans);
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--na-gray-light, #ccc);
}

.tv-qr__img {
  width: min(240px, 70vw);
  height: auto;
  background: #fff;
  padding: 12px;
  border-radius: 8px;
}

.tv-qr__row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

/* Whose HUD — first name and grade under the NA mark. Tap to switch. */
.tv-who,
button.tv-who {
  appearance: none;
  display: block;
  margin: 2px auto 0;
  padding: 0;
  border: 0;
  background: none;
  pointer-events: auto;
  cursor: pointer;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--na-gold, #fcb612);
  text-transform: none;
}

/* Hub unreachable: doors dimmed, one honest line at the foot of the page.
   Painted by doors.js, which is the only thing that knows the fetch failed. */
.os-door.is-dead {
  opacity: 0.28;
  pointer-events: none;
}

.tv-dead {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 60;
  margin: 0;
  max-width: min(92vw, 460px);
  padding: 10px 16px;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.82);
  color: var(--na-white, #fff);
  font-family: var(--sans);
  font-size: 13px;
  line-height: 1.45;
  text-align: center;
}
