/* site.css — admin_same: the one stylesheet every page of the site shares.
   Until now each page carried its own near-copy of these rules in its own
   <style>, and the copies had drifted: the admin page had a brown palette
   baked into :root that ignored the theme entirely, a 62px wordmark where
   the rest of the site has 68, and a 640px body where the rest has 760.
   Those are the differences you could see.

   What belongs here: the rules that are the same on every page — the reset,
   the page box, the wordmark, the header pair (cassette left, share right),
   the session drawer, and one_size. What stays in a page's own <style>: the
   things only that page has.

   It is linked BEFORE each page's <style>, so a page's own rule still wins
   at equal specificity. That is deliberate — the remaining pages still hold
   inline copies of some of these rules, and they can be deleted a page at a
   time without any page ever going through a state where it has neither.

   lab.html is the one page that does NOT link this. It is the experiment,
   and it is meant to look nothing like the site. */

/* the palette before theme.js speaks. theme.js sets these on the root element
   itself, which beats a stylesheet, so this is only what a page wears for the
   instant before it does — and what it wears if the script never arrives. Every
   page used to carry its own copy of this block. */
:root {
  --bg: #4a2a0e;
  --panel: #5c3717;
  --panel_2: #6b4423;
  --panel_3: #7a4f2a;
  --fg: #f5e5c5;
  --muted: #c9a87e;
  --accent: #e8b454;
  --accent_2: #d4a95a;
  --danger: #c75450;
  --warn: #e8c794;
}

* { box-sizing: border-box; }

html, body {
  background: var(--bg, #ffffff); color: var(--fg, #1d1d1f);
  margin: 0; padding: 0;
  /* tap_zoom: no double-tap zoom on a mis-hit; pinch still works */
  touch-action: manipulation;
}
/* tap_zoom: touch-action does not inherit, so the things you actually tap
   say it too — the drag handles keep their own 'none'. */
button, a, input, label, .jam_item, .tag_row, .mom_row { touch-action: manipulation; }

body {
  font: 15px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --gutter: 16px;
  padding: 3px var(--gutter) 24px;
  max-width: 760px; margin: 0 auto;
}

/* ---- the wordmark block at the top of every page ---- */
/* logo_line — the wordmark shares the top line with the two controls instead
   of starting below them. One row: cassette, wordmark, share. */
.brand {
  display: flex; align-items: center; justify-content: space-between;
  text-align: center; margin: 8px 0 6px;
}
.brand .wordmark {
  font-family: 'Sacramento', cursive;
  font-size: 68px; line-height: 1; color: var(--fg);
  flex: 1 1 auto; min-width: 0; text-align: center; margin: 0;
  /* nav_pair — four 40px targets leave about 230px on a 390px phone, and the
     wordmark is wider than that at 68px. It gives way rather than pushing the
     row off the screen. */
  white-space: nowrap;
}
@media (max-width: 430px) {
  .brand .wordmark { font-size: 54px; }
  .brand .wordmark_sf { font-size: 27px; }
}
/* record.html has a cassette and no share button; without this the wordmark
   centres in what is left and sits 20px right of true centre. */
.brand:not(:has(.nav_share)) .wordmark { margin-right: 40px; }
/* the markup puts both controls before the wordmark, so the row is ordered
   here rather than by moving the buttons in nine files. */
/* nav_pair — four controls now, two a side, with the wordmark holding the
   middle. Order, not markup: the buttons are written (or injected) in whatever
   sequence is convenient and land where they belong. */
.brand .nav_cass  { order: 1; }
.brand .nav_fav   { order: 2; }
.brand .wordmark  { order: 3; }
.brand .nav_rec   { order: 4; }
.brand .nav_share { order: 5; }
/* the injected pair are anchors wearing the buttons' clothes */
.brand .nav_fav, .brand .nav_rec, .brand .nav_rec_none { text-decoration: none; display: flex; align-items: center; justify-content: center; }
/* record.html writes its own favourites button (it has no drawer.js) */
.brand .nav_rec_none { order: 2; }
/* here_lit / nav_state — the header speaks in three colours and nothing else:
   BLUE   you are here
   RED    this is the recorder
   GREEN  that just happened
   Everything not saying one of those is the same muted grey. */
.brand .nav_on { color: var(--accent); pointer-events: none; }
.brand .nav_on:hover { color: var(--accent); }
/* a lit heart is FILLED, not outlined — the first path is the heart, the second
   is the three rules, which stay drawn as lines because that is what they are. */
.brand .nav_fav.nav_on svg path:first-child { fill: currentColor; }
/* the recorder is red when it is the page you are on. Blue would have said
   "current" in the same breath as the big red button below says "record", and
   only one of those two reds is allowed to mean recording. */
.brand .nav_rec.nav_on { color: #d70015; }
/* nav_hit — the share went. Dark green: the header's other two colours are
   places, this one is an event. */
.brand .nav_hit, .brand .nav_hit:hover { color: #0f6b3d; }
.brand .nav_cass.cass_live { color: var(--accent); }
.wordmark_sf {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 34px; font-weight: 650; letter-spacing: 0.5px; margin-left: 3px;
}
/* nav_room is gone: the pair no longer owns a band of its own, so the header
   only needs to clear the notch. That reclaims about 46px at the top of every
   page. */
.brand, .top_bar { padding-top: max(6px, env(safe-area-inset-top)); }

/* ---- the header pair: left is where you go, right is what you send ----
   26px glyph in a 40px target, muted, inside the header rather than pinned
   to the viewport, and both step out of the way while the list is open. */
.nav_cass, .nav_share {
  position: static; flex: 0 0 auto;
  background: transparent; color: var(--muted); border: none; border-radius: 7px;
  padding: 7px; min-height: 40px; min-width: 40px; cursor: pointer; line-height: 0;
  touch-action: manipulation;
}
.nav_cass:hover, .nav_share:hover { color: var(--fg); }
.nav_cass:active, .nav_share:active { transform: scale(0.96); }
.nav_cass svg, .nav_share svg { width: 26px; height: 26px; }
body.drawer_open .nav_cass, body.drawer_open .nav_share { opacity: 0; pointer-events: none; }

/* ---- session drawer: slides the page down from the top edge ---- */
.session_drawer {
  max-height: 0; overflow-y: auto; background: var(--bg);
  transition: max-height 0.18s ease; position: relative; z-index: 90;
}
.session_drawer.open { max-height: 80vh; max-height: 80dvh; }
/* control_panel_shadow: whatever is below casts a shadow UP from its top edge
   into the session list — row width, not full bleed, the whole time the list
   is open (it rides the bottom of the list's own scrollport). */
.session_drawer::after {
  content: ''; display: block; position: sticky; bottom: 0; z-index: 3;
  width: min(760px, 100%); margin: 0 auto -16px; height: 16px;
  border-radius: 0 0 14px 14px; pointer-events: none;
  background: linear-gradient(to top, rgba(0,0,0,0.22), rgba(0,0,0,0.10) 45%, rgba(0,0,0,0));
}
.session_drawer.dragging { transition: none; }
.session_drawer .jam_menu {
  position: static; top: auto; left: auto; min-width: 0;
  background: var(--panel); border: none; border-radius: 14px; overflow: hidden;
  box-shadow: inset 0 6px 7px -5px rgba(0,0,0,0.20);
  padding: 6px 0; margin: 12px auto 0; max-width: 760px;
}
/* land_drawer — in landscape split the session list opens as a sheet over the
   LEFT half only; the right half never moves */
@media (orientation: landscape) and (pointer: coarse) and (max-height: 520px) {
  .session_drawer { position: fixed; top: 0; left: 0; width: 50vw; z-index: 95;
                    box-shadow: 0 10px 26px rgba(0,0,0,0.3); border-radius: 0 0 14px 0; }
  .session_drawer.open { max-height: 88vh; }
}

/* ---- the session list itself ----
   list_css: these rows are drawn by drawer.js, which every page loads, but the
   rules that make them look like rows lived in each PAGE's own <style>. Any page
   that gained the drawer without also being handed a copy got the same list in
   raw HTML: blue underlined links, boxy buttons, no row height. That is exactly
   what happened to the admin page. The markup is shared, so the styling for it
   belongs with the markup, not with whichever page happens to be showing it.
   drawer.js still injects the rules that only IT knows about (the remove button,
   the hairlines, the title row, the scrolling name) on top of these. */
.jam_menu_overlay {
  display: none; position: fixed; inset: 0; z-index: 80;
  background: rgba(0,0,0,0.5); backdrop-filter: blur(4px);
}
.jam_menu_overlay.open { display: block; }
.jam_menu {
  position: absolute; top: 60px; left: 12px;
  background: var(--panel); border: 1px solid var(--panel_3);
  border-radius: 12px; padding: 6px; min-width: 220px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.5);
}
.jam_item { display: flex; align-items: center; min-height: 54px; box-sizing: border-box; padding: 0 12px; }
.jam_item:hover { background: var(--row_active); }
.jam_item.current { background: var(--row_active); }
.jam_item.jam_admin { border-top: 1px solid var(--panel_3); }
/* signin_show — sits with Admin at the foot of the list */
.jam_item.jam_signin { border-top: 1px solid var(--panel_3); }
.jam_item.jam_signin .jam_ico { color: var(--muted); }
.jam_link { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 10px;
            color: var(--fg); text-decoration: none; font-size: 17px; font-weight: 400; padding: 6px 0; }
.jam_link.current { color: var(--accent); font-weight: 600; }
.jam_link .menu_sub { display: inline; font-size: 17px; color: var(--muted); font-weight: 400; margin: 0; font-variant-numeric: tabular-nums; white-space: nowrap; }
.jam_left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.jam_name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jam_ico { flex: 0 0 auto; display: inline-flex; color: var(--accent); }
.jam_item.jam_admin .jam_ico { color: var(--muted); }
.jam_count { color: var(--muted); font-size: 14px; margin-left: 5px; }
/* new_dot — the REC button's red, spelled out rather than themed: a record
   dot is red in every palette, and this one has to read as the same object
   as the big circle on the record screen. (In the light theme --danger is
   already this exact hex; in the others it is not, which is the point.) */
.jam_item.jam_new .jam_ico { color: #d70015; }
.jam_ico svg { display: block; }
.jam_share { flex: 0 0 auto; background: transparent; color: var(--muted); border: none; border-radius: 7px;
             padding: 6px 6px; margin-left: 6px; min-height: 32px; cursor: pointer; line-height: 0; }
.jam_share:hover { background: transparent; color: var(--fg); }

/* the confirm sheet the remove control raises. Same reason: the drawer can raise
   it from any page, so any page has to be able to draw it. */
.jam_confirm_overlay { position: fixed; inset: 0; z-index: 120; background: rgba(0,0,0,0.5); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; }
.jam_confirm_card { background: var(--panel); color: var(--fg); border-radius: 14px; padding: 20px 22px; max-width: 320px; width: 84%; box-shadow: 0 12px 40px rgba(0,0,0,0.45); }
.jam_confirm_msg { margin-bottom: 16px; }
.jam_confirm_row { display: flex; gap: 10px; justify-content: flex-end; }
.jam_confirm_row button { border: none; border-radius: 10px; padding: 10px 16px; cursor: pointer; }
.jam_confirm_cancel { background: var(--panel_3); color: var(--fg); }
.jam_confirm_yes { background: var(--danger); color: #fff; }

#drawer_toggle { transition: none; }
.drawer_caret { transition: transform 0.3s ease; }
#drawer_toggle.open .drawer_caret { transform: rotate(180deg); }

/* one_size: a single text size for the whole app — only the vampSF wordmark
   (and glyph buttons whose icons scale with font-size) keep their own.
   icon_row: .play_tag and the highlight rows' ghost buttons join that list. Their
   icons are SVGs sized in em, so their font-size IS their icon size, and this rule
   was overriding it — the pages set 29px and 35px for them and got 17px, because
   this selector is both !important and far more specific than a class. That is how
   the highlight rows ended up with 17px icons beside 29px ones on the session
   rows, months after icon_grow was supposed to have made them one size. */
/* icon_miss — .fav_play_sm was not on this list and .fav_play does not match it,
   so the favourites row's triangle was taking 17px from here and its own
   35px !important was losing on specificity. Exactly the failure the note above
   describes, on the one row it had not been checked against. */
/* text_in_svg — a <text> inside an SVG is not an <svg>, so this rule was handing
   every label in every drawing 17px !important and overlapping them into mush.
   The exclusion has to name the element that carries the size, not its parent.
   Third time this list has been the bug: .play_tag, then .fav_play_sm, now text.
   And <g> has to be on it too, which is the part that took a second look: a
   drawing usually sets font-size on the GROUP and lets the labels inherit, so
   excluding <text> alone still handed the group 17px and the text inherited it. */
body :not(.wordmark):not(.wordmark_sf):not(.play_btn):not(.rec_btn):not(.fav_play):not(.fav_play_sm):not(.play_tag):not(.grade_pill):not(.ghost):not(svg):not(g):not(text):not(tspan) { font-size: 17px !important; }

/* icon_row — ONE row-icon size across the whole app. A session row's cassette and
   share are 29px; a highlight row's play, heart, share and remove are the same
   29px now, in targets of the same height. They are the same kind of thing on the
   same kind of row, and the eye compares them directly whenever the list slides
   over the highlights. */
/* del_same — a moment row on the record screen carries the same X as a
   highlight row, so it belongs to the same rule. Without this it was a
   .mom_del that one_size caught (17px) sitting where a 29px drawing goes. */
.tag_row button.ghost, .mom_row button.ghost { font-size: 29px !important; padding: 6px; min-height: 41px; line-height: 0; }
.tag_row button.play_tag { font-size: 29px !important; padding: 6px 8px 6px 2px; }

/* edit_wide — while you are typing a highlight's title, the field takes the
   whole row. Everything AFTER it steps out of the way: the timestamp, the end
   controls, the heart, the share, the remove. They are things you do to a
   highlight you have finished naming, and while the keyboard is up they are
   spending the width the words need. The number and the play button stay put, so
   the text does not jump sideways as you start.
   :focus-within rather than :has(), which is newer than it needs to be here; and
   :not(:focus) so a control that itself has focus is never the thing that
   vanishes under it. The row's own 12px padding is the "just shy of the edge". */
/* edit_only — row_more put the heart, share and remove inside one group, and
   :focus-within on the ROW hid that whole group the moment its share button
   took focus: the button was focused, its wrapper was not, and the wrapper is
   the sibling. The rule now hangs off the field itself, which is what it
   always meant: everything after the title steps aside while the TITLE has
   focus, and at no other time. */
.tag_row .tag_label:focus ~ * { display: none; }
/* and the open group, spelled out at the group's own specificity: row_more's
   inline-flex is declared later in this file and would otherwise win the tie */
.tag_row.acts_open .tag_label:focus ~ .tag_acts { display: none; }
/* and the same on a favourite. The shape differs in one way that matters: the
   field is wrapped in .fav_main rather than being a direct child of the row, so
   the sibling run starts from the WRAPPER. The controls that step aside are the
   cassette, the share and the heart — again, all things you do to a favourite you
   have finished naming.
   In reorder mode the field is readOnly and nothing in the row takes pointer
   events, so it can never be focused there and the two modes cannot collide. */
.fav_row .fav_main:focus-within ~ *:not(:focus) { display: none; }

/* row_grow — a new highlight opens rather than appearing. The list rebuilds its
   whole innerHTML on every render, so this cannot be "animate anything newly
   inserted" — every row would open every time. add_tag marks the ONE row it just
   made, and the class takes itself off at the end.
   height is animated in PIXELS, set from the row's measured height, because a
   height of auto is not a thing you can animate from 0 to. The row is clipped
   while it opens so its contents do not spill above the row before there is a
   row to hold them, and it fades and rises the last few pixels so the arrival
   has a direction. 0.5s, as asked. */
@keyframes tag_open {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.tag_row.tag_new {
  overflow: hidden;
  animation: tag_open 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
/* prefers-reduced-motion — someone who has asked the system for less movement
   gets the row, immediately, and no opinion about it */
@media (prefers-reduced-motion: reduce) {
  .tag_row.tag_new { animation: none; transition: none; }
}
/* and the favourites row's play is the same kind of thing on the same kind of
   row, so it is the same 29px in a target of the same height */
.fav_row button.fav_play_sm { font-size: 29px !important; padding: 6px 8px 6px 2px; min-height: 41px; line-height: 0; }
/* a ghost button anywhere else is a text control, not a row icon, and keeps the
   app size that one_size no longer hands it */
button.ghost { font-size: 17px; }

/* row_more — a row shows its title and three dots. The dots open into the
   row's actions with share at the far right; a tap anywhere else closes them.
   One button width competes with the title instead of three or four. */
/* gap: inherit — the group is a flex box inside a flex row; without its
   parent's gap the controls inside it sat 5px tighter than they did as
   direct children, and icon_snug's ratio was measured against the row's */
.jam_item .jam_acts, .tag_row .tag_acts { display: none; align-items: center; flex: 0 0 auto; gap: inherit; }
.jam_item.acts_open .jam_acts, .tag_row.acts_open .tag_acts { display: inline-flex; }
.jam_item.acts_open .jam_more, .tag_row.acts_open .tag_more { display: none; }
.jam_more { flex: 0 0 auto; background: none; border: none; color: var(--muted); opacity: 0.55;
            padding: 6px; min-height: 32px; cursor: pointer; line-height: 0; margin-left: auto; }
.jam_more:hover, .tag_row .tag_more:hover { opacity: 1; color: var(--fg); }
.tag_row .tag_more { opacity: 0.55; margin-left: auto; }
.tag_row .tag_acts button.ghost + button.ghost { margin-left: -4px; }   /* icon_snug, inside the group */

/* who_add — the list of numbers, at the bottom of the recording it governs.
   Uses .jam_* type sizing so the one_size rule in this file leaves it alone. */
.who_box { margin: 28px 16px 60px; padding: 16px; border: 1px solid var(--line);
           border-radius: 14px; background: var(--card); }
.who_box[hidden] { display: none; }
.who_h { margin: 0 0 6px; font-size: inherit; font-weight: 600; }
/* the line under the heading, which is the whole instruction */
.who_hint { color: var(--muted); margin: 0 0 10px; }
.who_hint[hidden] { display: none; }
/* who_me - the name the site knows you by, with the way to change it right
   beside it. He signed in and was called "you" for a week. */
.who_me { color: var(--muted); margin: 14px 0 0; font-size: 12.5px; }
.who_me[hidden] { display: none; }
/* Behind the sign-in there is nothing to administer, and two boxes saying
   "you are not signed in" is one box too many. */
body.gated .who_box { display: none; }
/* the access line, which is where a share dialog says who gets in. It reads
   after the box he types into, the way Google's does. */
.who_state { color: var(--muted); margin: 12px 0 10px; }
.who_state.shut { color: var(--fg); }
.who_list { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.who_chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 6px 4px 10px;
            border: 1px solid var(--line); border-radius: 999px; }
.who_last { color: var(--muted); }
.who_x { background: none; border: none; color: var(--muted); cursor: pointer;
         padding: 0 4px; line-height: 1; min-height: 28px; }
.who_x:hover { color: var(--fg); }
.who_in { display: block; width: 100%; box-sizing: border-box; padding: 10px 12px;
          border: 1px solid var(--line); border-radius: 10px; background: var(--bg);
          color: var(--fg); font-family: inherit; resize: vertical; }
.who_row { display: flex; gap: 8px; margin-top: 10px; align-items: center; }
.who_add { padding: 9px 16px; border: 1px solid var(--line); border-radius: 999px;
           background: var(--fg); color: var(--bg); cursor: pointer; font-family: inherit; }
.who_add[disabled] { opacity: 0.5; cursor: default; }
/* Copy link sits apart from Share: one hands you the thing to paste, the other
   decides who may open it. Same row, opposite weights. */
.who_copy { padding: 9px 14px; border: 1px solid var(--line); border-radius: 999px;
            background: none; color: var(--fg); cursor: pointer; font-family: inherit;
            margin-right: auto; }
.who_copy[hidden] { display: none; }
.who_note { margin-top: 8px; color: var(--muted); }
.who_note.bad { color: var(--accent-warn, #d7263d); }
.who_one { flex: 1 1 auto; width: auto; }
