/* style — the Luma Modify scrub player and keyframe bar.
   One section of the old style.css. The pieces load in filename order
   and that order is the cascade, so do not rearrange them. */
/* ---------- Luma Modify: wide scrub player + keyframe bar ---------- */
.luma-stage {
  position: relative; background: #000; overflow: hidden;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0; min-height: 110px;
}
.luma-vid { width: 100%; max-height: 280px; display: block; background: #000; cursor: pointer; }
.luma-loading {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.4); pointer-events: none;
}
/* Keyframe actions floating over the player, shown while the playhead is
   parked on a keyframe. The right offset clears the ✕ remove-clip button,
   which already owns the very corner. */
.luma-kfo {
  position: absolute; top: 6px; right: 38px; z-index: 4;
  display: flex; align-items: center; gap: 5px;
  padding: 3px 4px 3px 8px; border-radius: 3px;
  background: rgba(0, 0, 0, .62); border: 1px solid var(--border);
}
.luma-kfo.hidden { display: none; }
.luma-kfo-lab {
  font-size: 9px; letter-spacing: .3px; color: rgba(255, 255, 255, .82);
  font-family: "Geist Mono", Consolas, monospace; white-space: nowrap;
}
.luma-kfo .kfa { width: 20px; height: 20px; background: rgba(255, 255, 255, .13); }
.luma-kfo .kfa:hover { background: var(--accent); }
.luma-bar {
  position: relative; height: 26px; background: var(--card);
  border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  cursor: crosshair; touch-action: none; margin-bottom: 8px;
}
.luma-ph {
  position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px;
  background: #fff; box-shadow: 0 0 4px var(--scrim-mid); pointer-events: none; z-index: 2;
}
.luma-kfm {
  position: absolute; top: 50%; width: 11px; height: 11px; margin-left: -5.5px;
  transform: translateY(-50%) rotate(45deg);
  background: var(--accent); border: 2px solid #fff; border-radius: 2px;
  cursor: pointer; z-index: 3; box-shadow: 0 0 6px var(--accent-glow);
}
.luma-curlab {
  position: absolute; bottom: calc(100% + 4px); transform: translateX(-50%);
  background: rgba(0,0,0,.85); color: #fff; font-size: 9px; font-weight: 700;
  padding: 2px 6px; border-radius: 3px; white-space: nowrap; pointer-events: none; z-index: 4;
}
.luma-curlab.hidden { display: none; }
.gallery-head .sec-title { margin-bottom: 0; }
.gal-tools { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; justify-content: flex-end; }
.gfilter {
  display: flex; gap: 2px; background: var(--card);
  border: 1px solid var(--border); border-radius: 3px; padding: 2px;
}
.gfilter button {
  border: none; background: none; color: var(--text-dim); cursor: pointer;
  padding: 3px 7px; border-radius: 3px; line-height: 0;
}
.gfilter button svg { display: inline-block; vertical-align: middle; }
.gfilter button.active { background: var(--accent); color: #fff; }
/* ---- THE SIZE FILTER, AS A FILTER ----

   See the note in index.html. The pill is a funnel; the menu hangs under it
   on hover and on click both -- hover is what he asked for and is the quicker
   of the two, and click is what makes it usable from a trackpad and what
   keeps it open while you read it.

   The 8px bridge matters more than it looks: the menu is offset from the
   button so it does not sit on top of it, and without something covering that
   gap the menu closes as the pointer crosses it. */
.gfilter.gf-wrap { position: relative; }
.gf-wrap .gf-funnel { line-height: 0; }
.gf-wrap .gf-funnel.on { background: var(--accent); color: #fff; }
.gf-wrap:hover::after {
  content: ''; position: absolute; top: 100%; right: 0; width: 100%; height: 9px;
}
.gf-menu {
  position: absolute; top: 100%; right: 0; margin-top: 6px; min-width: 186px; z-index: 60;
  background: var(--card); border: 1px solid var(--border); border-radius: 3px;
  box-shadow: 0 10px 28px rgba(0,0,0,.55); padding: 4px; display: none; text-align: left;
}
.gf-wrap:hover .gf-menu, .gf-wrap.open .gf-menu { display: block; }
.gf-menu-t {
  font-size: 8.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-faint); padding: 5px 8px 4px;
}
.gfilter .gf-mi {
  display: flex; align-items: baseline; gap: 10px; width: 100%; box-sizing: border-box;
  line-height: 1.35; text-align: left; padding: 6px 8px; font-size: 11px; font-weight: 600;
}
.gfilter .gf-mi .s { font-size: 9px; font-weight: 500; color: var(--text-faint); margin-left: auto; }
.gfilter .gf-mi:hover { background: var(--card-hover, #26262c); color: var(--text); }
.gfilter .gf-mi.active { background: var(--accent); color: #fff; }
.gfilter .gf-mi.active .s { color: rgba(255,255,255,.78); }
/* The way out, written down, and never lit: it is the absence of a filter,
   and a menu whose "off" row is highlighted most of the time is a menu that
   looks like it is doing something. */
/* The sessions menu: an icon beside each name, and a caret on its door. */
.gf-views .gf-funnel { display: inline-flex; align-items: center; gap: 3px; }
.gf-views .gf-caret { opacity: .7; }
.gfilter .gf-mi .i { display: inline-flex; width: 12px; justify-content: center; line-height: 0; align-self: center; }
.gfilter .gf-mi .i svg { width: 11px; height: 11px; }
.gf-views .gf-menu { min-width: 200px; }
.gfilter .gf-clear {
  border-top: 1px solid var(--border); margin-top: 3px; padding-top: 7px;
  color: var(--text-faint); font-weight: 500;
}
.gfilter .gf-clear:hover { color: var(--text); background: none; }

/* "Inputs" filter — now an icon button, matching the other type filters. */
.gfilter .gf-inputs { line-height: 0; }
.gfilter .gf-inputs svg { display: inline-block; vertical-align: middle; }
.mbadge {
  flex: none; color: #3dff88;
  font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .6px;
}
/* WHAT ARRIVED IN THIS VERSION. Simon: "a little word saying 'new' written in
   the brand color, written next to it in the menu item."

   One rule for both surfaces -- the model list and the node menu -- because it
   is one idea, and two rules is how a mark ends up meaning two things. In the
   accent rather than .mbadge's green: green is a model's own standing label
   ("beta", a tier) and says something about the MODEL, where this says
   something about the RELEASE and goes away on the next one.

   Deliberately small and lowercase. It is a pointer, not an advertisement, and
   it sits beside a name that is the thing actually being read. */
/* "fast" beside the faster models (13-model-cards.js MODEL_FAST), in the brand colour. */
.mfast {
  flex: none; margin-left: 6px; color: var(--accent);
  font-size: 9px; font-weight: 800; letter-spacing: .6px; text-transform: uppercase;   /* Simon, 29 Sep: all capitals */
}
.covert-new {
  flex: none; margin-left: 6px;
  color: var(--accent);
  font-size: 8.5px; font-weight: 800; letter-spacing: .5px;
  text-transform: lowercase;
  vertical-align: 1px;
}
/* THE FULL WIDTH OF THE TILE, not as much of it as the shortest line needed.

   It was anchored on the left and left to size itself to its content, so the
   whole block was as wide as its widest line — and every OTHER line then had
   the ellipsis put on it at that width. The result was a model name cut short
   inside a panel with an inch of black to its right. Pinning both edges gives
   every line the whole card, which is the width that was always there. */
.ginfo {
  position: absolute; left: 4px; right: 4px; bottom: 4px; z-index: 2; display: none;
  flex-direction: column; gap: 1px;
  background: rgba(0, 0, 0, .74); color: #ddd;
  font-size: 9px; padding: 4px 7px; border-radius: 3px; pointer-events: none;
}
.ginfo span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* An empty line is still a line — the gap and the line-height are paid
   whether or not there is anything in it, so a clip whose duration never
   arrived showed a blank row where a number should be. */
.ginfo span:empty { display: none; }
/* Size and length share a line. A gap rather than a separator character —
   "1920×1080  4.0s" is already two facts to the eye, and a middot at 8px is
   a smudge. */
.ginfo .ginfo-line { display: flex; gap: 7px; align-items: baseline; }
/* The size takes what it needs and the length is never squeezed out: a clip
   whose length has been shortened to nothing is the one number you went
   looking for. */
.ginfo .ginfo-line > span:first-child { min-width: 0; }
.ginfo .ginfo-line > span + span { flex: none; color: var(--text-faint); }
.gal-item:hover .ginfo { display: flex; }
/* The price. Same strip as the size and the model, because they are all the
   same kind of fact — but green, because it is the one you go looking for. */
.ginfo .gcost { color: #7ee6a8; font-weight: 800; letter-spacing: .3px; }
/* Time sits beside cost and reads as the other half of the same sentence —
   what it cost you, and what it cost you to wait. Quieter than the money,
   because it is the less surprising of the two. */
.gtook { color: var(--text-dim); font-weight: 700; letter-spacing: .3px; }
/* Where it was made, on the same strip as everything else true about the
   file. Only ever appears on a node generation, so it reads as a fact about
   this one rather than as a column every card has to fill. */
.gnode {
  display: inline-flex; align-items: center; gap: 3px;
  color: var(--accent); font-weight: 800; letter-spacing: .3px;
}
.gnode em { font-style: normal; }
/* The "fitted on the way in" mark -- trimmed, rescaled, extended -- the
   sentence itself on hover (47-gallery-load.js, recipe.notice). */
.gfit { display: inline-flex; align-items: center; gap: 3px; color: var(--warn, #ffd35a); font-weight: 700; letter-spacing: .3px; cursor: help; }
.gfit em { font-style: normal; }
