/* surface-editor.css
   Scoped styling for the editor surface, loaded after css/orco.css so it inherits
   the material defined there: the gold hairline, gold focus, Georgia on his
   names, and the one primary action. Direction and reasoning:
   docs/beta-run/UX-VISUAL-DIRECTION.md

   This file exists so that four surfaces can be worked on at once without
   four seats editing one 4,250 line stylesheet. Everything here is scoped to
   this surface's own classes. Nothing here redefines a token. */

/* ==================================================================== *
 * 1. THE STATE DOCK: "Where this presentation lives"                   *
 * ==================================================================== *
 *
 * The defect this replaces: Save, the save status, the orco.vdr.me pill and
 * Publish sat side by side in one row wearing one shape, so four independent
 * facts read as four competing save buttons.
 *
 * They are now four named cells in one instrument panel that spans the foot
 * of the top bar. A cell is a DIMENSION, not a button: a small-caps label
 * that never changes, a sentence that does, and at most one action that acts
 * on that dimension alone. Reading left to right is reading outward, from the
 * copy under his hands to the copy a stranger can open:
 *
 *   Working copy  ->  Portable file  ->  Cloud copy  ->  Public link
 *
 * Nothing here merges two facts into one reassuring word. That rule is the
 * whole reason the panel exists.
 */

/* The top bar is allowed to grow by the height of the dock. Scoped to a class
   the editor adds itself, so a page without the dock keeps its 60px row. */
.app.has-lives { grid-template-rows: auto auto 1fr 30px; }

.lives {
  /* Its own line inside the top bar, at every width, bled to the bar's edges
     so it reads as a panel the bar sits on rather than a fifth toolbar. */
  flex: 1 1 100%;
  order: 99;
  display: grid;
  /* Not four equal quarters. The two cells that carry the longest honest
     sentences get the room, and the two that answer in four words give it up.
     Measured against "Not published from this browser" and the state model's
     own detail strings, not guessed. */
  grid-template-columns: 0.86fr 1.08fr 0.96fr 1.10fr;
  align-items: stretch;
  position: relative;
  /* Inset rather than bled to the bar's edges: the top bar's own padding is
     14px, 10px or 8px depending on width, so a fixed negative margin buys a
     few pixels of horizontal overflow at 390. Zero overflow wins. */
  margin: 3px 0 6px;
  border: 1px solid var(--hair);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.028) 0%, rgba(255, 255, 255, 0) 34%),
    rgba(6, 10, 26, 0.34);
}
/* The light theme is opt-in via an attribute; the absence of the attribute is
   the dark theme, so this selector must name light explicitly. */
[data-theme="light"] .lives { background: rgba(255, 255, 255, 0.42); }

/* The one ornament, and it is the product's own: a 10px gold L-bracket at the
   two outer bottom corners of the panel. It says "this is one object" without
   drawing a box around four things that are already separated by hairlines. */
.lives::before,
.lives::after {
  content: "";
  position: absolute;
  bottom: 0;
  width: 10px;
  height: 10px;
  pointer-events: none;
  border-bottom: 1px solid var(--gold-deep);
}
.lives::before { left: 0; border-left: 1px solid var(--gold-deep); }
.lives::after { right: 0; border-right: 1px solid var(--gold-deep); }

.lives-cell {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 1px;
  min-width: 0;
  padding: 6px 13px 7px;
  border-left: 1px solid var(--hair);
  transition: background var(--t-state) var(--ease);
}
.lives-cell:first-child { border-left: 0; }
.lives-cell:hover,
.lives-cell:focus-within { background: rgba(227, 200, 120, 0.045); }

/* The label never changes. It is the only fixed thing in the cell, which is
   what lets the sentence below it be read as an answer rather than a slogan. */
.lives-lab {
  font-size: 9.5px;
  font-weight: 660;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}
.lives-cell:hover .lives-lab,
.lives-cell:focus-within .lives-lab { color: var(--gold); }

.lives-body {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-width: 0;
  /* The action button is the tallest thing a body can hold, so every body
     reserves its height. Without this a cell with no button sits its
     elaboration 12px higher than its neighbours and the four lines that
     should read as one row read as four. */
  min-height: 28px;
}

/* The sentence. It WRAPS rather than clips, because a save status reading
   "Saved in this b" is the one string on this page that must never be cut. */
.lives-say {
  min-width: 0;
  flex: 1 1 auto;
  font-size: 13px;
  line-height: 1.24;
  font-weight: 520;
  color: var(--ink-2);
  white-space: normal;
  overflow-wrap: anywhere;
}

/* The two pills that came from the top bar lose their pill. Inside a labelled
   cell a border around the sentence is a second box saying the same thing. */
.lives .status {
  flex: 1 1 auto;
  min-width: 0;
  height: auto;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-radius: 0;
  font-size: 13px;
  line-height: 1.24;
  font-weight: 520;
  color: var(--ink-2);
  white-space: normal;
  text-align: left;
  align-items: flex-start;
  gap: 7px;
}
.lives .status:hover { background: none; box-shadow: none; }
/* In the dock there is room for the whole sentence at every width, so the
   short form is never needed and the long form is never hidden. */
.lives .status-short { display: none !important; }
.lives #status-text,
.lives #sync-text { display: inline !important; }

/* The state dot sits on the first line of a sentence that may wrap. */
.lives .status .dot { margin-top: 5px; flex: none; }
.lives .status { padding-top: 0; }
/* css/orco.css paints the settled dots with var(--good), which only exists in
   the light theme, so in the dark theme the "saved" and "synced" dots render
   transparent. Scoped fallback, not a token redefinition; the one line fix in
   css/orco.css is written out in this seat's report. */
.lives .status[data-state="saved"] .dot,
.lives .status[data-state="synced"] .dot { background: var(--ok); }

.lives-dot {
  flex: none;
  width: 7px;
  height: 7px;
  margin-top: 5px;
  border-radius: 50%;
  background: var(--ink-4);
  box-shadow: 0 0 0 3px rgba(135, 148, 181, 0.10);
}
.lives-dot[data-state="ok"] { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-bg); }
.lives-dot[data-state="warn"] { background: var(--warn); box-shadow: 0 0 0 3px var(--warn-bg); }
.lives-dot[data-state="bad"] { background: var(--bad); box-shadow: 0 0 0 3px var(--bad-bg); }
.lives-dot[data-state="wait"] { background: var(--ink-3); box-shadow: 0 0 0 3px rgba(135, 148, 181, 0.14); }

/* The action on a dimension. Quieter than a toolbar button, because the
   primary action of this surface is Present and nothing here competes. */
.lives .tool {
  flex: none;
  align-self: flex-start;
  margin-top: -1px;
  height: 28px;
  min-width: 0;
  padding: 0 10px;
  font-size: 12px;
  font-weight: 580;
  border-radius: var(--radius-sm);
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.lives .tool:hover:not(:disabled) {
  background: var(--surface-2);
  border-color: var(--hair-lit);
  box-shadow: none;
}
.lives .tool svg { opacity: 0.85; }

/* A REASON, NOT A GREY BUTTON. Where an action cannot run yet, the cell
   prints the prerequisite in the sentence and the button carries the same
   words in its tip. There is no unexplained disabled control in this panel. */
.lives .tool:disabled { opacity: 0.34; }

/* Still loading. For roughly 1.6s after a cold load the running order is
   genuinely short, and a graded answer in that window grades a different
   presentation. The panel says so, and the gold hairline breathes while it
   is true, which is the only motion in this surface. */
.lives[data-loading="yes"] { border-top-color: var(--hair-lit); }
.lives[data-loading="yes"]::before,
.lives[data-loading="yes"]::after { animation: lives-breathe 1.6s var(--ease) infinite; }
@keyframes lives-breathe {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.34; }
}

.lives-detail {
  color: var(--ink-3);
  font-size: 11px;
  line-height: 1.34;
  opacity: 1;
  /* Clamped to two lines, with the whole sentence on the cell's tooltip and
     in its title. The STATE line above is never clamped: that one is the
     claim, and a claim cut in half is a different claim. This is the
     elaboration, and two lines of it is what the bar can spend. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* A detail on its own line, under a sentence that has its own dot column, is
   indented to that column so the cell reads as one paragraph rather than two. */
.lives-cell > .lives-detail { padding-left: 17px; margin-top: 2px; }
.lives-cell > .lives-detail:empty { display: none; }
.lives-say b { font-weight: 620; color: var(--ink); }
.lives-say strong { font-weight: 620; color: var(--ink); }

/* An address is compared character by character, so it gets a monospace. */
.lives-url {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-3);
  text-decoration: none;
  border-bottom: 1px solid var(--hair);
  overflow-wrap: anywhere;
}
.lives-url:hover { color: var(--gold); border-bottom-color: var(--hair-lit); }

/* ==================================================================== *
 * 2. THE DISABLED DEAD ENDS                                            *
 * ==================================================================== *
 *
 * Five controls used to load disabled with no reason on screen. Three of them
 * belong to a selection that does not exist yet, so they are no longer drawn
 * until there is one. Two of them are undo and redo, which every editor draws
 * always, so they keep their seat and the group prints its own prerequisite
 * beside them until the first edit fills it.
 */
.selgroup {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.selgroup[hidden] { display: none; }

.histgroup {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.grouplab {
  font-size: 10px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  font-weight: 620;
  color: var(--ink-4);
  white-space: nowrap;
}
.grouplab[hidden] { display: none; }

/* ==================================================================== *
 * 3. WIDTHS                                                            *
 * ==================================================================== */

/* Four columns hold down to about 860px: at 1024 each cell is 246px, which
   takes "Not published from this browser" to two lines and its elaboration to
   two, and the whole dock to 89px. Two by two below that, because a third line
   in the claim is where it stops being readable. A dock that eats a quarter of
   the window is a worse answer than a dock that is one line taller. */
@media (max-width: 860px) {
  .lives { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lives-cell:nth-child(3) { border-left: 0; }
  .lives-cell:nth-child(n + 3) { border-top: 1px solid var(--hair); }
}

/* A finger. Every control in the panel clears 44px, and the sentence gets the
   whole width so nothing has to be guessed from an abbreviation. */
@media (max-width: 1000px), (pointer: coarse) {
  .lives .tool { height: 44px; padding: 0 12px; }
  /* 30px, not 44. These two are READOUTS first and doors second, which is the
     same floor test/e2e-mobile.mjs holds them to, and a fixed 44px box clipped
     the sentence the moment it ran to two lines. The sentence wins. */
  .lives .status { min-height: 30px; justify-content: flex-start; }
  .lives-cell { padding: 8px 14px; }
  .grouplab { display: none; }
}

/*
 * A phone. The four claims stay, all four of them, because which copy of the
 * work is safe is exactly the question a person asks on a phone. The
 * ELABORATIONS go: they are two lines each, four of them is 240px of a 844px
 * screen, and every one of them is still on the cell's tooltip and in its
 * title, so nothing the state model requires is unreachable. Measured on a
 * 390px viewport: 406px in one column with every elaboration drawn, 159px
 * folded like this, 271px when a person opens the fold on purpose.
 */
/* Above a phone the fold does not exist. */
.lives-more { display: none; }

@media (max-width: 620px) {
  /* One column, full sentences, no truncation anywhere. Two dimensions open,
     two behind the fold, and the fold wears their state as two dots. */
  .lives { grid-template-columns: minmax(0, 1fr); }
  .lives-cell {
    flex-direction: row;
    align-items: center;
    gap: 10px;
    padding: 6px 11px;
    border-left: 0;
  }
  .lives-cell + .lives-cell { border-top: 1px solid var(--hair); }
  .lives-lab { flex: none; width: 96px; letter-spacing: 0.09em; white-space: nowrap; }
  .lives-body { flex: 1 1 auto; }
  .lives-cell > .lives-detail { display: none; }

  .lives[data-expanded="no"] .lives-cell[data-dim="file"],
  .lives[data-expanded="no"] .lives-cell[data-dim="public"] { display: none; }

  .lives-more {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    min-height: 44px;
    padding: 0 11px;
    border: 0;
    border-top: 1px solid var(--hair);
    background: transparent;
    color: var(--ink-3);
    font: inherit;
    font-size: 12px;
    font-weight: 580;
    text-align: left;
    cursor: pointer;
  }
  .lives-more:hover { color: var(--ink-2); }
  .lives-more-dots { display: inline-flex; gap: 4px; }
  .lives-more .lives-dot { margin-top: 0; }
  .lives-more::after {
    content: "";
    margin-left: auto;
    width: 7px; height: 7px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform var(--t-state) var(--ease);
  }
  .lives[data-expanded="yes"] .lives-more::after { transform: rotate(-135deg) translate(-2px, -2px); }
}

@media (prefers-reduced-motion: reduce) {
  .lives, .lives-cell, .lives::before, .lives::after,
  .lives .tool, .lives-more, .lives-more::after { transition: none; animation: none; }
}

/* ==================================================================== *
 * 4. SEMANTIC COLOUR, USED ONLY AS STATE                               *
 * ==================================================================== *
 *
 * One green for settled, one amber for needs attention, one red for failed,
 * and never anything else. The claim line takes the colour only when the news
 * is not "fine": a panel where all four lines are tinted teaches nothing, and
 * a panel where one line is amber is read in a glance from across a room.
 */
.lives .status[data-state="error"],
.lives .status[data-state="conflict"],
.lives .status[data-state="refused"] { color: var(--bad); font-weight: 600; }
.lives .status[data-state="offline"] { color: var(--warn); }

.lives-cell[data-state="warn"] .lives-say b { color: var(--warn); }
.lives-cell[data-state="bad"] .lives-say b { color: var(--bad); }
