/* ==========================================================================
   BusayoDisu.com | the Learning Hub

   Loaded by learning-hub.html and by nothing else, so none of it costs a
   reader who never buys anything. It keeps the house typefaces and the
   house gold, and almost nothing else: the Hub is not a page of the site
   any more, it is the screen a licence opens onto, and it is dark in both
   of the site's appearances because a film and a black desk are what it
   holds.

   Three states, in the order a reader meets them:

     the door      one card in the middle of a dark room, the email already
                   in it and locked, and a password to choose
     the desktop   what they licensed, as things on a black desk. One click
                   picks a title up, two open it
     the player    the whole screen, one title at a time

   The player and the desktop are both fixed layers rather than pages, so
   closing a film puts the reader back on the desk exactly as they left it,
   with no load and no scroll position to guess at.
   ========================================================================== */

/* ==========================================================================
   THE SCREEN

   Everything the Hub wears is set here and answers to nothing else. The
   site has two appearances and a reader may choose either; this page has
   one, because it is not a page of the site. It is a screen: the dark room
   a film is watched in, and the dark desk a library sits on.
   ========================================================================== */

:root {
  --hub-bar: 44px;
  --hub-black: #04070B;
  --hub-room: #0D1826;
  --hub-ink: #EDF2F7;
  --hub-dim: #90A3B7;
  --hub-edge: rgba(237, 242, 247, 0.14);
  --hub-gold: #D9B368;
}

/* No margins, no rules, no furniture. Whatever main.css gives a reading
   page, this one gives back: there is nothing on the screen but the card
   in the middle of it, and later the desktop. */
body.hub-body {
  min-height: 100dvh;
  margin: 0;
  padding: 0;
  overflow-x: hidden;
  background: var(--hub-black);
  color: var(--hub-ink);
}

/* The room the card stands in. A little light above, as if from a window
   somewhere over the screen, so the middle of it is not flat black. */
body.hub-body #main {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: clamp(18px, 5vw, 44px);
  background:
    radial-gradient(120% 80% at 50% -18%, #16304A 0%, rgba(4, 7, 11, 0) 62%),
    var(--hub-black);
}

/* Once the desktop is up it is the whole screen and nothing behind it
   moves. */
body.hub-on { overflow: hidden; }

/* ==========================================================================
   THE DOOR

   One card, in the middle of the screen, and no other words anywhere. A
   reader arriving here has either followed a link from their inbox or come
   back to sign in, and both of those are a single question. Everything the
   page used to say around it, the steps, the questions, the invitation to
   buy, is said where somebody is deciding rather than where they are
   getting in.
   ========================================================================== */

.hub-door {
  width: min(420px, 100%);
  margin-inline: auto;
  border: 1px solid var(--hub-edge);
  border-radius: 18px;
  background: rgba(13, 24, 38, 0.86);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: 0 50px 100px -50px rgba(0, 0, 0, 0.95);
  padding: clamp(26px, 4vw, 38px);
  text-align: center;
}

.hub-mark {
  display: block;
  height: 30px;
  width: auto;
  margin: 0 auto 22px;
}

.hub-door h2 {
  font-family: var(--serif);
  font-size: clamp(1.5rem, 4vw, 1.9rem);
  line-height: 1.15;
  color: var(--hub-ink);
  margin: 0 0 8px;
}

.hub-door h2 em { font-style: italic; color: var(--hub-gold); }

.hub-door .hub-said {
  font-family: var(--sans);
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--hub-dim);
  margin: 0 0 24px;
}

.hub-door .hub-said a { color: var(--hub-gold); }

/* The address that paid, shown and not asked for. It is deliberately not a
   text input at all: a disabled box still reads as a thing somebody is
   meant to try to change, and this is the one field on the site that is a
   statement rather than a question. */
.hub-locked {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--hub-edge);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
  margin-bottom: 10px;
  word-break: break-all;
}

.hub-locked .hub-lock {
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  color: var(--hub-gold);
}

.hub-locked b {
  font-family: var(--sans);
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--hub-ink);
}

.hub-why {
  font-family: var(--sans);
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--hub-dim);
  margin: 0 0 20px;
}

.hub-why a { color: var(--hub-gold); }

/* The fields. The site's own are built for ivory, and every one of them
   would come out as a white box in a dark room. */
.hub-door form { margin: 0; }

.hub-door .field {
  display: grid;
  gap: 7px;
  margin-bottom: 18px;
  text-align: left;
}

.hub-door .field label {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hub-dim);
}

.hub-door input {
  width: 100%;
  padding: 13px 15px;
  border: 1px solid var(--hub-edge);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.05);
  color: var(--hub-ink);
  font-family: var(--sans);
  font-size: 1rem;
  color-scheme: dark;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
}

.hub-door input::placeholder { color: rgba(144, 163, 183, 0.7); }

.hub-door input:focus {
  outline: none;
  border-color: var(--hub-gold);
  box-shadow: 0 0 0 3px rgba(217, 179, 104, 0.24);
}

/* One way on, and it is gold, which is the only bright thing on the
   screen. Its own class rather than the site's .btn: the dark appearance
   in main.css repaints that one with a specificity nothing here can
   politely outrank, and a button on this screen is not the site's button. */
.hub-go {
  display: block;
  width: 100%;
  padding: 14px 20px;
  border: 0;
  border-radius: 10px;
  background: var(--hub-gold);
  color: #10202F;
  font-family: var(--sans);
  font-size: 0.96rem;
  font-weight: 600;
  letter-spacing: 0;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: transform .25s var(--ease), filter .25s var(--ease);
}

.hub-go:hover { filter: brightness(1.08); }
.hub-go:active { transform: translateY(1px); }
.hub-go:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(217, 179, 104, 0.4); }
.hub-go[disabled] { opacity: 0.5; cursor: default; }

.hub-msg {
  font-family: var(--sans);
  font-size: 0.88rem;
  line-height: 1.5;
  margin: 14px 0 0;
  min-height: 1.2em;
  color: var(--hub-dim);
}

.hub-msg.err { color: #E7A99B; }
.hub-msg.ok { color: #9FD4B4; }

.hub-alt {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid rgba(237, 242, 247, 0.1);
}

.hub-link {
  border: 0;
  padding: 0;
  background: none;
  font-family: var(--sans);
  font-size: 0.86rem;
  color: var(--hub-dim);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.hub-link:hover { color: var(--hub-gold); }
.hub-link:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(217, 179, 104, 0.4); border-radius: 4px; }

/* ==========================================================================
   THE DESKTOP

   What a licence holder gets after the password is not a web page about
   their library. It is their library: the things themselves, on a black
   desk, picked up with a click and opened with two.
   ========================================================================== */

.hub-desktop {
  position: fixed;
  inset: 0;
  z-index: 6;
  display: flex;
  flex-direction: column;
  background:
    radial-gradient(120% 60% at 50% 0%, #0C1B2B 0%, rgba(4, 7, 11, 0) 60%),
    var(--hub-black);
}

/* --- the strip along the top: whose desk this is, and the way out --- */
.hub-menu {
  flex: 0 0 auto;
  height: var(--hub-bar);
  display: flex;
  align-items: center;
  gap: 14px;
  padding-inline: clamp(12px, 2vw, 20px);
  background: rgba(8, 15, 24, 0.82);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid rgba(237, 242, 247, 0.1);
}

/* Square, where Busayo's mark was wide. Sized both ways rather than left
   to `width: auto`, so the row does not jump while the picture loads. */
.hub-menu-mark {
  height: 20px;
  width: 20px;
  display: block;
  border-radius: 5px;
  opacity: 0.95;
  flex: 0 0 auto;
}

.hub-menu-name {
  font-family: var(--sans);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--hub-ink);
}

.hub-menu-gap { flex: 1 1 auto; }

.hub-menu-who {
  font-family: var(--sans);
  font-size: 0.78rem;
  color: var(--hub-dim);
  max-width: 30ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Return to site is an anchor and the rest are buttons, so this has to
   hold both: no underline, and laid out rather than left inline, or the
   link sits a pixel or two off the row its neighbours are on. */
.hub-menu-key {
  border: 0;
  padding: 6px 10px;
  border-radius: 8px;
  background: none;
  color: var(--hub-dim);
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  text-decoration: none;
  transition: background .2s var(--ease), color .2s var(--ease);
}

.hub-menu-key:hover { background: rgba(237, 242, 247, 0.1); color: var(--hub-ink); }
.hub-menu-key:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--hub-gold); }

/* --- the desk itself ---

   Big. A cover here is the size of a thing you would pick up rather than
   the size of a favicon, because every one of these is a film or a book
   somebody paid for and the picture is how they know which.

   Filled across and then down, rather than down and then across, for one
   plain reason: a name is allowed to run to as many lines as it needs, so
   the rows are not all the same height and columns cannot be counted in
   advance. Nothing is ever shortened to a fit. */
.hub-field {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  padding: clamp(18px, 2.6vw, 34px);
  display: grid;
  grid-template-columns: repeat(auto-fill, 196px);
  gap: clamp(16px, 2vw, 26px) 8px;
  justify-content: start;
  align-content: start;
  user-select: none;
  -webkit-user-select: none;
}

.hub-icon {
  display: grid;
  justify-items: center;
  align-content: start;
  gap: 13px;
  width: 196px;
  padding: 12px 8px 10px;
  border: 0;
  border-radius: 16px;
  background: none;
  color: var(--hub-ink);
  font: inherit;
  cursor: pointer;
  transition: background .2s var(--ease);
}

.hub-icon:hover { background: rgba(237, 242, 247, 0.06); }
.hub-icon:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--hub-gold); }

.hub-tile {
  position: relative;
  width: 136px;
  height: 136px;
  border-radius: 26px;
  overflow: hidden;
  border: 1px solid rgba(237, 242, 247, 0.16);
  background: #10202F;
  box-shadow: 0 22px 40px -20px rgba(0, 0, 0, 0.95);
  transition: transform .2s var(--ease), border-color .2s var(--ease);
}

.hub-icon:hover .hub-tile { transform: translateY(-3px); }

.hub-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}

/* A title with no cover art yet still needs a face, and it gets the same
   one the licence card gives it: its own initial, in the brand's colour. */
.hub-art-flat {
  display: grid;
  place-items: center;
  height: 100%;
  background: #17324D;
  color: var(--hub-ink);
}

.hub-art-flat span {
  font-family: var(--serif);
  font-size: 4rem;
  line-height: 1;
  opacity: 0.55;
}

/* What this thing is, in the corner where a file's kind has always been
   said: watch it, read it, listen to it. */
.hub-type {
  position: absolute;
  inset: auto 8px 8px auto;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgba(6, 12, 20, 0.8);
  color: var(--hub-ink);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.hub-type svg { width: 17px; height: 17px; }

/* The whole name, however long it is. Nothing is cut to an ellipsis: a
   reader who has to hover an icon to find out which title it is has been
   given a puzzle instead of a library. */
.hub-name {
  font-family: var(--sans);
  font-size: 0.9rem;
  line-height: 1.35;
  text-align: center;
  padding: 4px 9px;
  border-radius: 8px;
  max-width: 180px;
  overflow-wrap: break-word;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}

/* Picked up, but not yet opened. The same two states a desktop has always
   had, and the gold is the site's own rather than a system blue. */
.hub-icon.on .hub-tile { border-color: var(--hub-gold); }
.hub-icon.on .hub-name { background: var(--hub-gold); color: #10202F; text-shadow: none; }

/* Started and not finished. No number, because we know where a reader
   stopped and not how long the thing runs, and a bar drawn from one of
   those two is a guess wearing a measurement. */
.hub-icon.started .hub-tile::after {
  content: "";
  position: absolute;
  inset: auto 14px 12px 14px;
  height: 4px;
  border-radius: 2px;
  background: var(--hub-gold);
}

/* Bought, and not loaded in yet. It stays on the desk, because it was
   bought, and it says so when it is opened. */
.hub-icon.soon .hub-tile { filter: grayscale(0.7) brightness(0.55); }
.hub-icon.soon .hub-name { color: var(--hub-dim); }

/* Nothing licensed to this address yet. The one case where the desk has
   words on it. */
.hub-empty {
  flex: 1 1 auto;
  display: grid;
  place-items: center;
  padding: 24px;
  text-align: center;
}

.hub-empty h2 {
  font-family: var(--serif);
  font-size: clamp(1.4rem, 4vw, 1.8rem);
  color: var(--hub-ink);
  margin: 0 0 10px;
}

.hub-empty p {
  font-family: var(--sans);
  font-size: 0.92rem;
  color: var(--hub-dim);
  margin: 0 0 22px;
}

.hub-empty a {
  font-family: var(--sans);
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--hub-gold);
}

/* ==========================================================================
   A PANEL

   The two things on this screen that are neither a title nor the door: the
   answers to the questions a licence holder actually asks, and the desk
   Busayo sends somebody their library from. Both open on the desktop, the
   way anything else opens on a desktop, rather than living further down a
   page that no longer scrolls.
   ========================================================================== */

.hub-panel {
  position: fixed;
  inset: 0;
  z-index: 950;
  display: grid;
  place-items: center;
  padding: clamp(14px, 3vw, 34px);
}

.hub-panel-scrim {
  position: absolute;
  inset: 0;
  border: 0;
  padding: 0;
  background: rgba(2, 5, 9, 0.72);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  cursor: default;
}

.hub-panel-card {
  position: relative;
  width: min(640px, 100%);
  max-height: min(80dvh, 760px);
  display: flex;
  flex-direction: column;
  border: 1px solid var(--hub-edge);
  border-radius: 16px;
  background: var(--hub-room);
  box-shadow: 0 50px 100px -50px rgba(0, 0, 0, 0.95);
  overflow: hidden;
}

.hub-panel-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px 14px 22px;
  border-bottom: 1px solid rgba(237, 242, 247, 0.1);
}

.hub-panel-head h2 {
  flex: 1 1 auto;
  font-family: var(--serif);
  font-size: 1.25rem;
  line-height: 1.2;
  margin: 0;
  color: var(--hub-ink);
}

.hub-panel-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: clamp(18px, 2.6vw, 26px);
}

.hub-panel-body h3 {
  font-family: var(--sans);
  font-size: 0.94rem;
  font-weight: 600;
  color: var(--hub-ink);
  margin: 0 0 6px;
}

.hub-panel-body p {
  font-family: var(--sans);
  font-size: 0.9rem;
  line-height: 1.65;
  color: var(--hub-dim);
  margin: 0 0 22px;
}

.hub-panel-body p:last-child { margin-bottom: 0; }
.hub-panel-body a { color: var(--hub-gold); }

/* The send desk keeps the door's fields, inside the panel. */
.hub-panel-body .field { display: grid; gap: 7px; margin-bottom: 18px; }

.hub-panel-body .field label {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hub-dim);
}

.hub-panel-body input[type="email"] {
  width: 100%;
  padding: 13px 15px;
  border: 1px solid var(--hub-edge);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.05);
  color: var(--hub-ink);
  font-family: var(--sans);
  font-size: 1rem;
  color-scheme: dark;
}

.hub-panel-body input[type="email"]:focus {
  outline: none;
  border-color: var(--hub-gold);
  box-shadow: 0 0 0 3px rgba(217, 179, 104, 0.24);
}

.hub-picks {
  border: 1px solid var(--hub-edge);
  border-radius: 10px;
  padding: 12px 14px 14px;
  margin: 0 0 20px;
  display: grid;
  gap: 2px;
}

.hub-picks legend {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hub-dim);
  padding-inline: 6px;
}

.hub-picks label {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 4px;
  font-family: var(--sans);
  font-size: 0.92rem;
  color: var(--hub-ink);
  cursor: pointer;
  border-radius: 6px;
}

.hub-picks label:hover { background: rgba(237, 242, 247, 0.07); }

.hub-picks input {
  width: 17px;
  height: 17px;
  accent-color: var(--hub-gold);
  color-scheme: dark;
  flex: 0 0 auto;
}

/* ==========================================================================
   SMALL SCREENS

   A phone has no double click, so one tap opens a title there. See
   js/hub.js. What changes here is the shape: icons flow across rather than
   down, because a short screen makes columns of two and then runs off the
   side.
   ========================================================================== */

@media (max-width: 720px) {
  :root { --hub-bar: 42px; }

  /* Two to a row on a phone, and the icons give up their fixed width so
     the row divides evenly however wide the handset is. The tile shrinks;
     the name does not, because the name is the thing being read. */
  .hub-field {
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 18px 6px;
  }

  .hub-icon { width: auto; }
  .hub-tile { width: 108px; height: 108px; border-radius: 22px; }
  .hub-name { font-size: 0.86rem; max-width: 100%; }
  .hub-menu-who { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hub-icon,
  .hub-tile,
  .hub-door input,
  .hub-go,
  .hub-menu-key { transition: none; }
  .hub-icon:hover .hub-tile { transform: none; }
}

/* ==========================================================================
   THE PLAYER

   A layer over everything, dark, so a film is watched against a dark room
   rather than against a bright website. This is the one place on the site
   that deliberately does not wear the ivory.
   ========================================================================== */

.hub-stage {
  position: fixed;
  /* Everything below the Desktop bar, which stays. The player is a window
     on that desktop, not a thing that swallows it. */
  inset: var(--hub-bar) 0 0 0;
  /* Above the header, the menu and the floating appearance control, and
     below the editor's own popup, which has to be able to reach anything.
     A film with a website's furniture floating on it is not a film. */
  z-index: 960;
  display: none;
  flex-direction: column;
  background: #0B1725;
  color: #EAF0F5;
}

.hub-stage.open { display: flex; }
body.hub-playing { overflow: hidden; }
body.hub-playing .theme-fab { display: none; }

/* --- the bar across the top --- */
.hub-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px clamp(14px, 2.4vw, 26px);
  border-bottom: 1px solid rgba(234, 240, 245, 0.12);
}

.hub-bar .hub-bar-said { min-width: 0; flex: 1 1 auto; }

.hub-bar h2 {
  font-family: var(--serif);
  font-size: clamp(1.05rem, 2.6vw, 1.5rem);
  line-height: 1.15;
  margin: 0;
  color: #EAF0F5;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hub-bar .hub-where {
  font-family: var(--sans);
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #93A7BA;
}

/* Every control in the player is one of these. Round, quiet, and the same
   size everywhere so the row reads as a row. */
.hub-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 44px;
  padding: 0 18px;
  border-radius: 999px;
  border: 1px solid rgba(234, 240, 245, 0.24);
  background: transparent;
  color: #EAF0F5;
  font-family: var(--sans);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  transition: background .25s var(--ease), border-color .25s var(--ease), color .25s var(--ease), opacity .25s var(--ease);
}

.hub-key:hover { background: rgba(234, 240, 245, 0.12); border-color: rgba(234, 240, 245, 0.5); }
.hub-key:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--gold); }
.hub-key[disabled] { opacity: 0.32; cursor: default; }
.hub-key[disabled]:hover { background: transparent; border-color: rgba(234, 240, 245, 0.24); }
.hub-key svg { width: 17px; height: 17px; flex: 0 0 auto; }

.hub-key.round { padding: 0; width: 44px; }
.hub-key.gold { background: var(--gold); border-color: var(--gold); color: #17324D; }
.hub-key.gold:hover { background: #D9B368; border-color: #D9B368; }
.hub-key.on { background: rgba(200, 155, 69, 0.2); border-color: var(--gold); color: var(--gold); }

/* --- the middle: whatever is being played, read or listened to --- */
.hub-play {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;

  /* How wide the picture may be. Sixteen by nine, until the window is
     shorter than that allows, and then it is the height that decides — so
     the width is worked out from the height here, once, and the words
     underneath are given the same column. Without that the picture shrinks
     on a short screen and the paragraph below it does not, and the two stop
     lining up on the very screens where the mismatch is most visible.

     The 290px is everything that is not the picture: the Desktop bar, the
     title bar, the row of controls and enough of the description to show
     that there is one. */
  --gut: clamp(14px, 2.4vw, 26px);
  --film: min(1200px, calc((100vh - var(--hub-bar) - 290px) * 16 / 9));
  --film: min(1200px, calc((100dvh - var(--hub-bar) - 290px) * 16 / 9));
}

.hub-screen {
  position: relative;
  width: 100%;
  max-width: calc(var(--film) + var(--gut) * 2);
  margin: clamp(14px, 2vw, 26px) auto 0;
  padding-inline: var(--gut);
}

/* Always sixteen by nine. What stops it filling a laptop window to the last
   pixel, and pushing what the film is about off the bottom, is the column
   width set on .hub-play above rather than a ceiling here, so the picture
   keeps its shape and the words keep its edges. */
.hub-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  background: #05101B;
}

.hub-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* The activity that comes after the film. Same frame, taller, because a set
   of questions is a page and not a picture. */
.hub-frame.tall { aspect-ratio: auto; height: min(72vh, 760px); background: var(--ivory); }

.hub-waiting {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 24px;
  text-align: center;
  color: #93A7BA;
  font-family: var(--sans);
  font-size: 0.95rem;
}

/* --- what the title is about --- */
.hub-about {
  width: 100%;
  max-width: calc(var(--film) + var(--gut) * 2);
  margin-inline: auto;
  padding: clamp(20px, 3vw, 32px) var(--gut) clamp(28px, 4vw, 44px);
  display: grid;
  gap: 18px;
}

.hub-about h3 {
  font-family: var(--sans);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0;
}

.hub-about p {
  margin: 0;
  max-width: 74ch;
  color: #C7D5E1;
  font-size: clamp(0.95rem, 1.7vw, 1.02rem);
  line-height: 1.7;
}

.hub-themes { display: flex; flex-wrap: wrap; gap: 9px; list-style: none; margin: 0; padding: 0; }

.hub-themes li {
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 600;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid rgba(234, 240, 245, 0.2);
  color: #C7D5E1;
}

/* --- the row of controls at the foot --- */
.hub-feet {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 14px clamp(14px, 2.4vw, 26px);
  border-top: 1px solid rgba(234, 240, 245, 0.12);
  background: #0B1725;
}

.hub-feet .hub-spacer { flex: 1 1 auto; }

/* On a phone the row becomes two: the two arrows on the outside of a
   middle that holds everything else, which is the shape a thumb expects. */
@media (max-width: 600px) {
  .hub-feet { gap: 8px; padding: 10px 12px 14px; }
  .hub-key { font-size: 0.84rem; padding: 0 14px; min-height: 42px; }
  .hub-key .hub-key-word { display: none; }
  .hub-key.keep-word .hub-key-word { display: inline; }
}

/* ==========================================================================
   READING

   The book is opened from a pass that lasts minutes, held in memory, and
   turned page by page. Nothing is written to the reader's machine, and
   there is no address on the page that would still work tomorrow.
   ========================================================================== */

.hub-read {
  width: 100%;
  max-width: 1100px;
  margin: clamp(14px, 2vw, 26px) auto 0;
  padding-inline: clamp(14px, 2.4vw, 26px);
}

/* The page, and then room underneath it for the row that turns the text
   bigger and opens the contents. Measured from the window rather than as a
   share of it, because the bar above and the row of controls below are
   fixed heights and it is what is left over that the page gets. */
.hub-page {
  position: relative;
  height: min(calc(100vh - var(--hub-bar) - 265px), 820px);
  height: min(calc(100dvh - var(--hub-bar) - 265px), 820px);
  min-height: 320px;
  border-radius: var(--radius);
  background: var(--paper, #FAF7F2);
  overflow: hidden;
  transition: background .3s var(--ease);
}

/* The two papers. Set here as well as inside the book, because the sheet
   the book is drawn on is this element and the reader sees it a moment
   before the first chapter arrives; a white flash on the way into a dark
   page is the one thing a dark page must not do. */
.hub-read[data-paper="light"] { --paper: #FAF7F2; --paper-ink: #17324D; }
.hub-read[data-paper="dark"] { --paper: #111E2C; --paper-ink: #DCE5EC; }

/* One page at a time is what a book is, and it is the default. A single
   column across the full width of a desk monitor is a line nobody can
   read, so in one-page the sheet is held to the width of a page. Two
   pages already divides the width in half and needs no help. */
.hub-read[data-pages="one"] .hub-page {
  max-width: 660px;
  margin-inline: auto;
}

.hub-page > div { height: 100%; }

.hub-turn {
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(38px, 6vw, 64px);
  border: 0;
  background: transparent;
  color: var(--paper-ink, #17324D);
  cursor: pointer;
  display: grid;
  place-items: center;
  opacity: 0.35;
  transition: opacity .25s var(--ease), background .25s var(--ease), color .3s var(--ease);
  z-index: 2;
}

.hub-turn:hover { opacity: 1; background: rgba(127, 127, 127, 0.1); }
.hub-turn:focus-visible { outline: none; opacity: 1; box-shadow: inset 0 0 0 3px var(--gold); }
.hub-turn.back { left: 0; }
.hub-turn.on { right: 0; }
.hub-turn svg { width: 22px; height: 22px; }

/* Full screen. The player is normally hung below the site's own bar; with
   the screen to itself there is no bar to hang below, and the page takes
   back the height the bar and the margins were using. */
.hub-stage:fullscreen { inset: 0; }
.hub-stage:-webkit-full-screen { inset: 0; }

.hub-stage:fullscreen .hub-page {
  height: min(calc(100vh - 210px), 1000px);
  height: min(calc(100dvh - 210px), 1000px);
}

.hub-stage:-webkit-full-screen .hub-page {
  height: min(calc(100vh - 210px), 1000px);
}

.hub-stage:fullscreen .hub-read[data-pages="one"] .hub-page { max-width: 760px; }

.hub-read-feet {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 14px;
  font-family: var(--sans);
  font-size: 0.84rem;
  color: #93A7BA;
}

.hub-read-feet .hub-spacer { flex: 1 1 auto; }

/* Back and Next kept together, so the pair reads as one control and wraps
   to the next line as one rather than splitting across two. */
.hub-pair {
  display: inline-flex;
  gap: 6px;
  align-items: center;
}

.hub-pair .hub-key svg { width: 16px; height: 16px; }

/* The contents. A list, over the page, because a book without one is a
   scroll. */
.hub-toc {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: none;
  background: rgba(11, 23, 37, 0.96);
  padding: clamp(18px, 3vw, 30px);
  overflow-y: auto;
}

.hub-toc.open { display: block; }
.hub-toc ol { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }

.hub-toc button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 12px 14px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: #EAF0F5;
  font-family: var(--sans);
  font-size: 0.94rem;
  cursor: pointer;
}

.hub-toc button:hover { background: rgba(234, 240, 245, 0.1); }
.hub-toc button:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--gold); }

/* ==========================================================================
   LISTENING

   Our own controls rather than the browser's, for one plain reason: the
   browser's carry a download button. What is left is a picture, a line to
   drag, and the two skips a listener actually uses.
   ========================================================================== */

.hub-listen {
  width: 100%;
  max-width: 640px;
  margin: clamp(20px, 4vw, 48px) auto 0;
  padding-inline: clamp(14px, 2.4vw, 26px);
  text-align: center;
}

.hub-sleeve {
  width: min(320px, 68vw);
  aspect-ratio: 1;
  margin: 0 auto clamp(22px, 4vw, 36px);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 30px 60px -30px rgba(0, 0, 0, 0.8);
  background: var(--forest);
}

.hub-sleeve img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The line. One input, drawn, because a range input left to the platform
   looks like a different website in every browser. */
.hub-line {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 22px;
  background: transparent;
  cursor: pointer;
  display: block;
}

.hub-line::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(to right, var(--gold) var(--played, 0%), rgba(234, 240, 245, 0.2) var(--played, 0%));
}

.hub-line::-moz-range-track { height: 6px; border-radius: 3px; background: rgba(234, 240, 245, 0.2); }
.hub-line::-moz-range-progress { height: 6px; border-radius: 3px; background: var(--gold); }

.hub-line::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -5px;
  border-radius: 50%;
  background: var(--gold);
  border: 0;
}

.hub-line::-moz-range-thumb { width: 16px; height: 16px; border-radius: 50%; background: var(--gold); border: 0; }
.hub-line:focus-visible { outline: none; }
.hub-line:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 4px rgba(200, 155, 69, 0.4); }

.hub-clock {
  display: flex;
  justify-content: space-between;
  font-family: var(--sans);
  font-size: 0.82rem;
  color: #93A7BA;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}

/* Under a recording the words come back to the middle. A film is as wide
   as the screen and its description sits under the left edge of it; a
   sleeve is a square in the centre, and a paragraph starting a long way
   out to the left of it reads as belonging to something else. */
.hub-listen + .hub-about { max-width: 720px; }

.hub-listen-keys {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: clamp(18px, 3vw, 28px);
  flex-wrap: wrap;
}

.hub-big {
  width: 68px;
  height: 68px;
  padding: 0;
  border-radius: 50%;
  background: var(--gold);
  border-color: var(--gold);
  color: #17324D;
}

.hub-big:hover { background: #D9B368; border-color: #D9B368; }
.hub-big svg { width: 26px; height: 26px; }

/* --- the two tabs a book with a recording gets --- */
.hub-tabs {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border-radius: 999px;
  border: 1px solid rgba(234, 240, 245, 0.2);
}

.hub-tabs button {
  min-height: 36px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #C7D5E1;
  font-family: var(--sans);
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
}

.hub-tabs button[aria-selected="true"] { background: var(--gold); color: #17324D; }
.hub-tabs button:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--gold); }

/* ==========================================================================
   THE RUNNING ORDER

   A drawer, from the right, holding the queue this title belongs to. It is
   the one place a reader can change the order Next walks in, so it has to
   be plain that the up and down arrows are the point.
   ========================================================================== */

.hub-queue {
  position: absolute;
  inset: 0 0 0 auto;
  z-index: 4;
  width: min(420px, 100%);
  display: flex;
  flex-direction: column;
  background: #101F31;
  border-left: 1px solid rgba(234, 240, 245, 0.14);
  transform: translateX(100%);
  transition: transform .4s var(--ease);
}

.hub-queue.open { transform: translateX(0); }

.hub-queue-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 18px;
  border-bottom: 1px solid rgba(234, 240, 245, 0.12);
}

.hub-queue-head h3 {
  flex: 1 1 auto;
  font-family: var(--serif);
  font-size: 1.1rem;
  margin: 0;
  color: #EAF0F5;
}

.hub-queue-list { flex: 1 1 auto; overflow-y: auto; padding: 10px; margin: 0; list-style: none; }

.hub-queue-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  border-radius: var(--radius-sm);
}

.hub-queue-list li.now { background: rgba(200, 155, 69, 0.14); }

.hub-queue-list .hub-q-open {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
  border: 0;
  background: transparent;
  color: #EAF0F5;
  font-family: var(--sans);
  font-size: 0.92rem;
  cursor: pointer;
  padding: 6px 4px;
}

.hub-queue-list .hub-q-open span {
  display: block;
  font-size: 0.76rem;
  color: #93A7BA;
  margin-top: 3px;
}

.hub-queue-list li.now .hub-q-open { color: var(--gold); }
.hub-queue-list .hub-q-open:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--gold); border-radius: 6px; }

.hub-q-move {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 32px;
  height: 30px;
  padding: 0;
  border: 1px solid rgba(234, 240, 245, 0.2);
  border-radius: 7px;
  background: transparent;
  color: #C7D5E1;
  cursor: pointer;
}

.hub-q-move:hover { background: rgba(234, 240, 245, 0.12); }
.hub-q-move[disabled] { opacity: 0.25; cursor: default; }
.hub-q-move[disabled]:hover { background: transparent; }
.hub-q-move svg { width: 14px; height: 14px; }
.hub-q-move:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--gold); }

.hub-queue-foot {
  flex: 0 0 auto;
  padding: 14px 18px;
  border-top: 1px solid rgba(234, 240, 245, 0.12);
  font-family: var(--sans);
  font-size: 0.82rem;
  color: #93A7BA;
}

/* The screen behind the drawer, so a tap anywhere else closes it. */
.hub-scrim {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: none;
  border: 0;
  padding: 0;
  background: rgba(5, 16, 27, 0.6);
  cursor: pointer;
}

.hub-scrim.open { display: block; }

/* ==========================================================================
   MOTION

   The cut motion budget from the 2026 brief applies here too: everything
   above is a fade, a lift or a slide, nothing loops, and anybody who has
   asked their machine for less gets none of it.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .hub-queue,
  .hub-key,
  .hub-turn { transition: none; }
  .hub-queue { transition: none; }
}
