/* ============================================================================
   gg-components.css  —  the GG shared COMPONENT layer.
   One source of truth for the controls every GG app reuses (jumpcut.GG /
   bitcrush.GG / boxout.GG): buttons, cards, panels, list rows, chips,
   segmented toggles, tabs. Built entirely from the tokens in gg-theme.css, so
   a skin (data-gg-theme token swap) restyles all of it everywhere at once.

   Load order:  fonts.css → gg-theme.css → gg-components.css → themes/*.css → gg-ui.js
   (themes come last so they can override these component rules per skin.)

   THE NON-GHOST LAW: an interactive control is a SOLID surface (var(--raise),
   guaranteed a step above --card) with a real edge and a hard offset shadow for
   physical separation. No transparent-fill + hairline-outline "ghost" buttons.
   When you genuinely want a borderless/transparent control, opt IN with .ghost.
   ============================================================================ */

/* ============================ BUTTONS ====================================== */
/* THE CURSOR LAW: `cursor:pointer` means HYPERLINK. A native application shows
   the arrow over its buttons, rows, chips, tabs, sliders and menu items - the
   hand is the browser's "this navigates" affordance, and putting it on every
   control is one of the loudest tells that a desktop app is a web page. Only
   .gg-link (a link that leaves the app) gets the hand; everything else is
   cursor:default. Swept 2026-08-23 - 67 rules across the kit and app.css. If a
   control needs to advertise itself, it does that with a hover surface step,
   not by changing the pointer. */
/* ONE definition of a button, in two places that must agree.
   <gg-button> renders a real <button> inside a shadow root, which document CSS
   cannot reach, so the kit carries a second copy of these rules in
   gg-components.js. They had drifted - sm was `3px 8px / 11px` here and
   `0 11px / 12px` there, and only the shadow copy had the shared control
   height - meaning a <button class="sm"> and a <gg-button size="sm"> were
   different controls, and a token pass would have moved one and not the other.
   Same values, same --gg-btn-* hooks, both copies, from 2026-08-23.
   tools/preflight.py's `kit` check fails the build if they diverge again. */
button, .gg-btn {
  display:inline-flex; align-items:center; justify-content:var(--gg-btn-justify, center); gap:7px;
  min-height:var(--gg-btn-h, var(--ctl-h, 30px));   /* shared control height - aligns with selects/inputs */
  color:var(--gg-btn-fg, var(--text));
  background:var(--gg-btn-bg, var(--raise));
  border:var(--gg-btn-border, none);
  border-radius:var(--gg-btn-radius, var(--radius,8px));
  padding:var(--gg-btn-pad, 7px 13px);
  font-family:var(--f-body); font-size:var(--gg-btn-fs, var(--fs-control,12px)); font-weight:700;
  line-height:1.1; cursor:default; white-space:nowrap; text-decoration:none;
  /* DEPTH (DESIGN-2.0-PLAN.md): a button inside a panel is FLAT - the surface step is its
     edge. The 1px offset is for the primary action and a dialog's footer (`raised`); the
     soft drop is for things that float. A dozen small shadows in one toolbar was noise. */
  box-shadow:var(--gg-btn-shadow, none);
  transition:transform .05s ease, box-shadow .05s ease, background .12s, border-color .12s, color .12s; }
/* NO border-color on a state. The kit's buttons are border:none, so this was
   inert for them - but ANY app control that borrows the `button` selector and
   reserves its own 1px (`.cs-toolbtn`, `.look-strip .lk`, `.cs-zoom button`,
   `.proj-name`) had that pixel ignited from here on hover. That is where the
   thin outlines kept coming back from after each sweep removed the app-level
   rule: the kit put one straight back (owner, 2026-08-23). Hover is the
   surface step, nothing else. */
button:hover, .gg-btn:hover { background:var(--raise-hi); }
button:focus-visible, .gg-btn:focus-visible { outline:none; box-shadow:0 0 0 3px rgba(var(--lime-rgb),.4); }
button:disabled, .gg-btn:disabled, .gg-btn.disabled {
  opacity:.45; cursor:default; box-shadow:none; transform:none; }

/* --- variants --- */
button.primary, .gg-btn.primary { background:var(--lime); color:var(--on-lime); border-color:var(--lime); font-weight:700; box-shadow:1px 1px 0 rgba(0,0,0,.3); }
button.primary:hover, .gg-btn.primary:hover { background:var(--lime); filter:brightness(1.08); }
button.danger, .gg-btn.danger { background:var(--danger); color:var(--on-danger); border-color:var(--danger); font-weight:700; box-shadow:1px 1px 0 rgba(0,0,0,.3); }
button.danger:hover, .gg-btn.danger:hover { background:var(--danger-hi); }
button.warn, .gg-btn.warn, button.gg-cancel { background:var(--warn); color:#1f0d06; border-color:var(--warn); font-weight:700; box-shadow:1px 1px 0 rgba(0,0,0,.3); }
button.raised, .gg-btn.raised { box-shadow:1px 1px 0 rgba(0,0,0,.3); }   /* a dialog's footer buttons */
button.warn:hover, .gg-btn.warn:hover, button.gg-cancel:hover { filter:brightness(1.08); }
button.accent2, .gg-btn.accent2 { background:var(--accent2); color:#fff; border-color:var(--accent2); }

/* Pressed is PAINT ONLY: the shadow drops and the surface steps down a shade.
   Nothing moves. The old rule translated 2px down-and-right, which slid a thin
   control out from under the pointer - the mouseup landed elsewhere and the
   click never fired (owner, 2026-08-23, on the 16px Import options
   disclosure). Brightness rather than opacity: opacity washes the label out
   against a dark surface, while a tonal step is what def2 uses everywhere else.
   Placed AFTER the variants deliberately - .primary:hover also sets a filter at
   the same specificity, and you are always hovering while you press, so an
   earlier rule would simply lose. */
button:active, .gg-btn:active { box-shadow:0 0 0 rgba(0,0,0,0); filter:brightness(.93); }

/* --- intentional ghost: borderless/transparent, opt-in only (icon toolbars) --- */
button.ghost, .gg-btn.ghost { background:transparent; border-color:transparent; box-shadow:none; color:var(--text2); font-weight:600; }
button.ghost:hover, .gg-btn.ghost:hover { background:var(--control); color:var(--text); border-color:transparent; }

/* An icon is never the thing clicked: the control around it is. With typed characters a
   click landed on the button (a text node is not a target); with an element inside, it
   would land on the icon, and every handler that tests `e.target` against the control's
   own class would miss. So the icon takes no pointer events at all. */
gg-icon { pointer-events:none; }

/* --- sizes --- */
button.sm, .gg-btn.sm, button.tiny { padding:0 11px; font-size:var(--fs-control,12px); }
button.lg, .gg-btn.lg { padding:10px 18px; font-size:var(--fs-body,13px); min-height:0; }
button.icon, .gg-btn.icon { padding:0; width:34px; height:34px; min-height:0; flex:0 0 auto; }
button.sm.icon, .gg-btn.sm.icon { width:26px; height:26px; }
.gg-btn.block { display:flex; width:100%; }

/* ============================ SURFACES ===================================== */
/* selectable list row (clip lists, layer lists, recent items, …).
   Selection = solid inset accent edge, never a thin outline — same design as the
   <gg-row> component (this is the plain-markup twin for JS-built lists). */
/* THE LIST ROW (DESIGN-2.0-PLAN.md): one row for projects, exports, restore points, and (as
   they move onto it) clips, layers and plugins. A mark or nothing, a name, values in mono on
   the right. Four states, all of them fills: rest is the panel showing through, hover and
   selected step the surface, off is dimmed. `.two` is a name over a line of values. It
   replaces rows that were each their own rounded card with a gap between - a list read as a
   stack of buttons. */
.gg-list { display:flex; flex-direction:column; gap:1px; }
.gg-list-row { display:flex; align-items:center; gap:9px; width:100%; min-height:30px; padding:0 10px; box-sizing:border-box;
               background:transparent; border:none; border-radius:var(--radius,5px); box-shadow:none;
               color:var(--text); font-family:var(--f-body); font-size:var(--fs-body,13px); font-weight:500; text-align:left;
               cursor:default; transition:background .12s; }
.gg-list-cols { display:flex; align-items:center; gap:9px; height:26px; padding:0 10px; box-sizing:border-box;
                font-family:var(--f-mono); font-size:var(--fs-label,10px); letter-spacing:.12em; text-transform:uppercase; color:var(--text2); }
.gg-list-cols > :first-child { flex:1 1 auto; min-width:0; }
.gg-list-row:hover { background:var(--control); }
.gg-list-row.selected, .gg-list-row.selected:hover { background:var(--card-sel); }
.gg-list-row.off { color:var(--muted); }
.gg-list-row.two { min-height:44px; }
.gg-list-row .gg-lr-main { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:3px; }
.gg-list-row .gg-lr-name { font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.gg-list-row .gg-lr-meta { font-family:var(--f-mono); font-size:var(--fs-label,10px); color:var(--text2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.gg-row { display:flex; align-items:center; gap:10px; background:var(--card);
          border-radius:var(--radius); padding:8px 10px;
          cursor:default; transition:background .12s, box-shadow .12s; }
.gg-row:hover { background:var(--card-sel); }
.gg-row.selected, .gg-row.active { background:var(--card-sel); box-shadow:inset 0 0 0 2px var(--lime); }

/* ============================ CHIPS / BADGES =============================== */
.gg-chip { display:inline-flex; align-items:center; gap:6px; background:var(--chip);
           border:none; border-radius:999px; padding:4px 11px;
           font-family:var(--f-mono); font-size:var(--fs-data,11px); color:var(--text2); white-space:nowrap; }
.gg-chip.on { background:var(--lime); color:var(--on-lime); }
/* (.gg-badge lives in gg-theme.css) */

/* ============================ CHROME (v0.4) ================================ */
/* jumpcut.GG's product chrome, promoted so every GG app can recreate its look:
   context menu, progress (spinner / bar / steps / queue), empty states,
   edge-docked cards, the start screen "desktop", dialog internals, labels.
   Values match jumpcut.GG exactly — consuming apps restyle via tokens. */

/* ---- right-click / dropdown menu ---- */
.gg-menu-backdrop { position:fixed; inset:0; z-index:300; }
.gg-menu { position:fixed; min-width:200px; background:var(--card); border:none;
           border-radius:var(--radius-lg,9px); padding:4px; box-shadow:0 12px 32px rgba(0,0,0,.55); }
/* A row is 26px (DESIGN-2.0-PLAN.md). It was about 33: a web dropdown's proportions, and a
   menu of twelve commands stood 480px tall. A native menu runs 24 to 26. */
.gg-menu-item { display:flex; align-items:center; justify-content:space-between; gap:20px; height:26px; padding:0 10px; box-sizing:border-box;
                border-radius:var(--radius,5px); font-size:var(--fs-body,13px); color:var(--text); cursor:default; white-space:nowrap; }
/* .at is the KEYBOARD cursor - arrow keys walk the rows and it must paint the
   same as the pointer, or a menu driven from the keyboard looks unresponsive */
.gg-menu-item:hover, .gg-menu-item.at { background:var(--control); }
.gg-menu-item.danger { color:var(--danger); }
.gg-menu-item.disabled { opacity:.4; cursor:default; pointer-events:none; }
.gg-menu-item .gg-menu-lbl { display:flex; align-items:center; gap:8px; min-width:0; }
.gg-menu-item .gg-menu-ico { flex:0 0 auto; color:var(--text2); --gg-icon-size:14px; width:14px; }
/* in a menu where SOME rows have an icon, every row keeps the column, so labels line up */
.gg-menu-item .gg-menu-ico.none { display:inline-block; height:1px; }
.gg-menu-item:hover .gg-menu-ico, .gg-menu-item.at .gg-menu-ico { color:var(--text); }
.gg-menu-item .gg-menu-kbd { font-family:var(--f-mono); font-size:var(--fs-label,10px); color:var(--muted); }
.gg-menu-item .gg-menu-right { display:flex; align-items:center; gap:8px; }   /* kbd + submenu arrow as one aligned cell */
.gg-menu-item .gg-menu-arrow { display:inline-flex; color:var(--text2); --gg-icon-size:11px; }
.gg-menu-item .gg-menu-check { flex:0 0 auto; color:var(--lime); font-size:var(--fs-label,10px); width:12px; text-align:center; }
.gg-menu-item.has-sub { position:relative; }
.gg-menu-sub { position:absolute; left:100%; top:-6px; display:none; max-height:60vh; overflow-y:auto; z-index:1; }
.gg-menu-item.has-sub:hover > .gg-menu-sub, .gg-menu-sub:hover { display:block; }   /* contiguous (no gap) so the cursor can reach it */
.gg-menu.flip-sub .gg-menu-sub { left:auto; right:100%; }
.gg-menu-div { height:1px; background:var(--divider); margin:4px 8px; }
.gg-menu-head { display:flex; align-items:center; height:22px; padding:0 10px; font-family:var(--f-mono); font-size:var(--fs-label,10px);
                letter-spacing:.14em; text-transform:uppercase; color:var(--text2); }

/* ---- application menu bar ---- */
/* A top-level menu name is NOT a button - it has no fill, no radius at rest,
   no control height, and its whole job is to be a flat word that lights up.
   So it resets the kit's button base rather than being a gg-button variant.
   It opens a .gg-menu, which is why it is defined here beside it. */
.gg-menubar { display:flex; align-items:stretch; gap:0; min-height:26px; flex:0 0 auto; }
.gg-menubar .gg-mb-top { all:unset; display:flex; align-items:center; padding:0 10px;
                         font:inherit; font-size:var(--fs-control,12px); color:var(--text2);
                         cursor:default; user-select:none; border-radius:var(--radius,5px);
                         transition:background 120ms, color 120ms; }
.gg-menubar .gg-mb-top:hover { color:var(--text); background:var(--control); }
/* .on = this menu's dropdown is open. Holds the lit state while the pointer is
   down in the list below, so the bar keeps showing where the menu came from. */
.gg-menubar .gg-mb-top.on { color:var(--text); background:var(--card);
                            border-radius:var(--radius,5px) var(--radius,5px) 0 0; }

/* ---- progress: spinner, bar, step list, import queue ---- */
.gg-spin { width:var(--gg-spin-size,16px); height:var(--gg-spin-size,16px); flex:0 0 var(--gg-spin-size,16px);
           border-radius:50%; border:2px solid var(--border); border-top-color:var(--lime);
           animation:gg-spin .8s linear infinite; }
@keyframes gg-spin { to { transform:rotate(360deg); } }
.gg-bar { height:var(--gg-bar-h,7px); border-radius:var(--radius,5px); background:var(--well); overflow:hidden; }
.gg-bar-fill { display:block; height:100%; width:0%; border-radius:var(--radius,5px); background:var(--lime); transition:width .25s ease; }
.gg-bar.indet .gg-bar-fill { width:35% !important; animation:gg-indet 1.1s ease-in-out infinite; }
@keyframes gg-indet { 0%{margin-left:-35%;} 100%{margin-left:100%;} }
.gg-steps { display:flex; flex-direction:column; gap:9px; }
.gg-step { display:flex; align-items:center; gap:9px; font-size:var(--fs-body,13px); color:var(--muted); }
.gg-step .gg-ring { width:15px; height:15px; flex:0 0 15px; border-radius:50%; border:2px solid var(--border); position:relative; }
.gg-step.active { color:var(--text); }
.gg-step.active .gg-ring { border-top-color:var(--lime); animation:gg-spin .8s linear infinite; }
.gg-step.done { color:var(--text2); }
.gg-step.done .gg-ring { background:var(--lime); border-color:var(--lime); }
.gg-step.done .gg-ring::after { content:"✓"; position:absolute; inset:0; display:flex; align-items:center;
                                justify-content:center; font-size:var(--fs-label,10px); color:var(--on-lime); }
.gg-queue-item { display:flex; align-items:center; gap:9px; padding:3px 0; font-size:var(--fs-control,12px); color:var(--text); }
.gg-queue-dot { width:7px; height:7px; flex:0 0 7px; border-radius:50%; background:var(--border); }
.gg-queue-item.active .gg-queue-dot { background:var(--lime); animation:gg-pulse 1s ease-in-out infinite; }
.gg-queue-item.done .gg-queue-dot { background:var(--lime); }
.gg-queue-item.fail .gg-queue-dot { background:var(--danger); }
@keyframes gg-pulse { 0%,100%{opacity:1;} 50%{opacity:.3;} }
.gg-queue-name { flex:1 1 auto; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-family:var(--f-mono); }
.gg-queue-state { flex:0 0 auto; font-size:var(--fs-data,11px); color:var(--muted); }
.gg-queue-item.fail .gg-queue-state { color:var(--danger); }

/* ---- empty state (each app supplies its own glyph/illustration above) ---- */
.gg-empty { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px;
            text-align:center; color:var(--muted); padding:34px 22px; }
.gg-empty-title { font-family:var(--f-head); font-weight:600; font-size:var(--fs-title,15px); color:var(--text2); }
.gg-empty-hint { font-size:var(--fs-control,12px); max-width:230px; line-height:1.45; }
.gg-empty-hint b { color:var(--text2); }

/* ---- edge-docked floating card (flush to a window edge; inner corners round) ---- */
.gg-dock { position:absolute; top:50%; transform:translateY(-50%); background:var(--panel);
           box-shadow:0 12px 36px rgba(0,0,0,.45); }
.gg-dock.l { left:0; border-radius:0 var(--radius-lg,9px) var(--radius-lg,9px) 0; }
.gg-dock.r { right:0; border-radius:var(--radius-lg,9px) 0 0 var(--radius-lg,9px); }

/* ---- start screen: the app "desktop" (landing overlay) ---- */
.gg-start { position:fixed; inset:0; z-index:100050; display:none; flex-direction:column;
            align-items:center; justify-content:center;
            background:var(--well); }   /* flat: it was a radial wash, a landing page's backdrop */
.gg-start.show { display:flex; }
.gg-start-card { width:480px; max-width:92vw; display:flex; flex-direction:column; align-items:stretch;
                 gap:14px; padding:30px 30px 26px; }
.gg-start-input { flex:1 1 auto; min-width:0; height:46px; padding:0 14px; font-size:var(--fs-body,13px);
                  font-family:var(--f-body); color:var(--text); background:var(--inset);
                  border:none; border-radius:var(--radius-lg,9px); outline:none; }
.gg-start-input::placeholder { color:var(--faint); }
.gg-start-input:focus { box-shadow:0 0 0 2px rgba(var(--lime-rgb),.4); }
.gg-or { display:flex; align-items:center; gap:12px; color:var(--faint); font-size:var(--fs-data,11px);
         font-family:var(--f-mono); text-transform:uppercase; letter-spacing:.16em; }
.gg-or::before, .gg-or::after { content:""; flex:1; height:1px; background:var(--divider); }
.gg-start-foot { position:absolute; bottom:14px; left:50%; transform:translateX(-50%);
                 font-family:var(--f-mono); font-size:var(--fs-data,11px); color:var(--faint); z-index:2; }
.gg-start-ver { position:absolute; bottom:14px; right:18px; font-family:var(--f-mono);
                font-size:var(--fs-label,10px); color:var(--faint); z-index:2; }
/* The ONE place the hand cursor belongs: a link that leaves the app. See the
   cursor law at the top of the buttons section. */
.gg-link { color:inherit; cursor:pointer; text-decoration:none; }
.gg-link:hover { color:var(--lime); text-decoration:underline; }

/* ---- dialog internals (confirm / prompt inside a .gg-card) ---- */
.gg-ask-msg { color:var(--text2); font-size:var(--fs-body,13px); line-height:1.5; margin:2px 0 14px; }
.gg-ask-input { width:100%; box-sizing:border-box; margin:0 0 14px; }
.ask-check { display:flex; align-items:center; gap:7px; margin:0 0 14px; font-size:var(--fs-control,12px); color:var(--muted); cursor:default; }
.gg-ask-actions { display:flex; justify-content:flex-end; gap:8px; }
/* a dialog's Done: closes the dialog it is in (the handler is one delegated listener) */
.gg-foot-note { margin-right:auto; }   /* a summary on the footer's left, actions on its right */

/* ---- labels / header furniture ---- */
.gg-hdr-sep { flex:0 0 auto; align-self:center; width:1px; height:20px; background:var(--border); }

/* ============================ CHROME (v0.5) ================================ */
/* ---- media transport bar (player controls strip under a video) ----
   Buttons are gg-buttons carrying .gg-tp-btn; seek/volume are native ranges
   carrying .gg-tp-seek / .gg-tp-vol. Track + fill come from the base range
   style (accent fill via --rng; unfilled colour via the --rng-track theme
   token) — the fill doubles as the seek/level indicator. Thumb restyle via
   --gg-tp-thumb. */
.gg-transport { display:flex; align-items:center; gap:10px; padding:8px 14px;
                background:var(--panel); flex:0 0 auto; }
.gg-tp-btn { --gg-btn-pad:4px 8px; --gg-btn-fs:15px; }   /* gg-button host sizing */
.gg-tp-time { font-family:var(--f-mono); font-size:var(--fs-data,11px); color:var(--text2);
              min-width:46px; text-align:center; }
input.gg-tp-seek, input.gg-tp-vol { height:4px; border-radius:var(--radius-sm,3px); }
.gg-tp-seek { flex:1 1 auto; }
.gg-tp-vol { flex:0 0 84px; }
input.gg-tp-seek::-webkit-slider-thumb, input.gg-tp-vol::-webkit-slider-thumb {
  -webkit-appearance:none; appearance:none; width:12px; height:12px; border-radius:50%;
  background:var(--gg-tp-thumb, #fff); border:none; cursor:default; }
input.gg-tp-seek::-moz-range-thumb, input.gg-tp-vol::-moz-range-thumb {
  width:12px; height:12px; border-radius:50%;
  background:var(--gg-tp-thumb, #fff); border:none; cursor:default; }
