/* ---------------------------------------------------------------------
   The Thinking Surface — appearance.

   SPEC-thinking-surface-v0.1 §8. Four decisions carry the requirement
   that it must not read as another panel, and none of them is colour:
   no chrome, it overlaps, no cards, and the ink fades.

   Every value here is the locked system. Nothing new. The one addition
   is the paper, #fffefb — a breath of warmth, deliberately not a cream
   ground, which the design research names as the default tell.
   --------------------------------------------------------------------- */

.ts-root {
  --ts-paper: #fffefb;
  --ts-gold: #b8883a;
  --ts-rule: #e4e7ea;
  --ts-mute: #8a9096;

  /* The application is capped and centred above 1400px, so the window's
     right edge and the application's right edge are different things on
     a wide monitor. Ruled by Gerry, 10 August 2026: the sheet follows
     the application.

     Pinned to the window, the sheet sat in the margin with a field of
     white between it and the work — which breaks §8.1 outright, because
     a sheet laid ON the application cannot be laid on nothing. The
     max() collapses to the plain 30px inset whenever the window is
     narrower than the cap. */
  /* Amended 12 August 2026. The cap was removed from the application, so
     the window's right edge and the application's right edge are now the
     same thing and the sum below collapses to the plain inset. Kept as a
     variable rather than deleted: if a cap is ever reintroduced, this is
     the one place that has to change for the sheet and the tab to follow
     it again. */
  --ts-app-max: 100%;
  /* Percentage rather than 100vw, deliberately. 100vw includes the
     scrollbar's width, while a fixed element's right edge sits inside
     it — so the sheet and the tab shifted about eight pixels sideways
     on every screen that scrolls, and some screens set overflow:hidden
     while others do not. A percentage resolves against the containing
     block, which excludes the scrollbar, so the position stops moving
     as you navigate. */
  --ts-edge: max(30px, calc((100% - var(--ts-app-max)) / 2 + 30px));

  /* §8.1 — a sheet laid on the desk, floating clear on all four sides.
     The gap is what stops it reading as a panel: a panel is flush and
     joined to what it sits beside. This is not joined to anything. */
  position: fixed;
  right: var(--ts-edge);

  /* Amended 13 August 2026. At top:28px the sheet sat over the nav and
     the signed-in name was behind it. The nav is 56px of content on a
     1px rule, and the first-session screen puts a 32px orientation strip
     above that — 28px of strip on 6px of padding, so 40px — and the
     sheet is fixed, so one value has to clear the deepest of them: 56
     of nav, 1 of rule, 40 of strip, then the same 28px of air it has on
     the other three sides. Still floating clear on all four sides —
     §8.1 is untouched. This lowers the sheet; it does not join it to
     anything. First measured at 89px, which cleared the nav on eight
     screens and sat on the strip on the ninth. */
  top: 125px;
  bottom: 28px;

  /* Scaled rather than fixed, same date. 366px was a third of the 1118px
     shell it was drawn in and a seventh of a 2500px window, which is why
     it read as an afterthought once the application filled the screen.
     The floor is the drawn width, so nothing narrows; the ceiling stops
     it becoming a pane in its own right, which §8.1 forbids. */
  width: clamp(366px, 24vw, 520px);
  z-index: 60;
  display: flex;
  flex-direction: column;

  /* §8.1 — laid ON the application, not joined to it. No border-left, no
     shared rule, no alignment to the panes. Two shadows: tight for the
     contact edge, wide for the lift. */
  background: var(--ts-paper);
  border-radius: 2px;
  box-shadow:
    0 1px 2px rgba(22, 25, 28, 0.07),
    0 26px 60px -12px rgba(22, 25, 28, 0.20),
    0 0 0 0.5px rgba(22, 25, 28, 0.06);

  font-family: 'Inter', -apple-system, sans-serif;
  /* Laid down, not installed. A tenth of a degree is below the threshold
     of looking crooked and above the threshold of looking placed. */
  transform: rotate(-0.12deg);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s ease;
}

/* §9 §6.1 — the obvious implementation is a right-hand panel, and a
   right-hand panel is the failure mode. It is not one because it floats
   and sits askew; and it still collapses entirely, leaving nothing but
   a way back. */
.ts-root[data-state='closed'] {
  transform: translateX(calc(100% + var(--ts-edge))) rotate(-0.12deg);
  opacity: 0;
  pointer-events: none;
}

/* The way back. Present only when the sheet is away.
   
   Two changes, 10 August 2026. It sits at the application's right edge
   rather than the window's, for the same reason the sheet does — in the
   margin of a wide monitor it was 500px from anything. And it is
   darker: at #c9ced3 on white it was not restrained, it was hidden, and
   the surface is now away on arrival so this is the only way in.

   Amended 12 August 2026. The application's right edge was computed
   from a 1400px shell. The shell is no longer capped, so that sum put
   the tab in the middle of a comparison table — inside the content
   rather than beside it. The application now fills the window, so the
   window's edge and the application's edge are the same thing. */
.ts-reopen {
  /* ADDED 16 August 2026. --ts-rule is declared on .ts-root, at the top
     of this file. thinking-surface-ui.js appends this button to
     appRoot — document.body — which is a SIBLING of .ts-root, not an
     ancestor. So var(--ts-rule) has never resolved here.

     An unresolved var() invalidates the whole shorthand at
     computed-value time and every longhand falls back to its initial
     value, including border-style:none. Confirmed in a browser on
     16 August: "style none, width 0px, colour rgb(122, 130, 144)" —
     that colour being currentColor from this same rule.

     So the way back has been an invisible white rectangle since it was
     written. That is why the text it covers has read as clipped rather
     than as covered. It is also the same complaint the note above
     records one level up: the label was darkened on 10 August because
     at #c9ced3 it was hidden rather than restrained, and the border
     silently vanished in the same edit.

     Declared here rather than moved to :root so the token stays where
     the surface owns it. The other two uses of --ts-rule are inside the
     sheet and resolve correctly; this was the single point of failure. */
  --ts-rule: #e4e7ea;

  position: fixed;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 59;
  writing-mode: vertical-rl;
  padding: 20px 9px;
  background: #ffffff;
  border: 1px solid var(--ts-rule);
  border-right: 0;
  border-radius: 3px 0 0 3px;
  cursor: pointer;
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #7a8290;
}
.ts-reopen:hover { color: #16191c; border-color: #c9ced3; }
.ts-reopen:focus-visible { outline: 2px solid var(--ts-gold); outline-offset: 2px; }

/* §8.1 — the name once, faint, in the corner. The only chrome on the
   sheet, and it is an annotation rather than a title bar: a title bar is
   the single element that makes a thing read as a module. */
.ts-tab {
  position: absolute;
  top: 9px;
  left: 20px;
  /* The target was the text itself, about 90 by 10 pixels. Padded out
     so it can be hit deliberately rather than precisely. */
  padding: 6px;
  background: none;
  border: 0;
  cursor: pointer;
  /* §8.1 — the name appears once, faintly, as a pencil annotation in the
     corner of the sheet. Not a title bar; a title bar is the single
     element that makes a thing read as a module, and paper has none. */
  font-family: 'Inter', sans-serif;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #c9ced3;
}
.ts-tab:hover { color: var(--ts-mute); }
.ts-tab:focus-visible { outline: 2px solid var(--ts-gold); outline-offset: 2px; }

/* Put it away.
   
   Amends §8.1, 10 August 2026. That section forbids chrome on the
   grounds that a title bar is what makes a thing read as a module, and
   it made the faint name in the corner do double duty as the control.
   Gerry failed to find it twice in one session — the first time looking
   for a way to close the sheet, the second looking for a way back. A
   control nobody can find is not restraint.
   
   This does not reintroduce a title bar. It follows §8.5, which already
   sets the pattern for this surface: no controls at rest, and the acts
   appear on hover. The name stays and stays clickable; this is the
   second way in, for the person who has not been told. */
.ts-close {
  position: absolute;
  top: 8px;
  right: 10px;
  width: 26px;
  height: 26px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 3px;
  cursor: pointer;
  font-family: 'Inter', sans-serif;
  font-size: 16px;
  line-height: 1;
  color: #a0a8b0;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease;
}
.ts-root:hover .ts-close { opacity: 1; }
.ts-close:hover { color: #16191c; background: #f4f5f6; }
.ts-close:focus-visible { opacity: 1; outline: 2px solid var(--ts-gold); outline-offset: 1px; }

.ts-sheet {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
  padding: 44px 26px 12px;
  /* §8.4 — oldest at the top, today at the bottom, nearest the hand.
     flex-end keeps the newest against the write area when the sheet is
     not yet full, rather than stranding it at the top of empty paper. */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.ts-empty {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-size: 13.5px;
  color: #a0a8b0;
  padding: 18px 0 24px;
}

/* §8.1 — no cards. Blocks of writing separated by space. */
.ts-note {
  position: relative;
  padding: 0 0 26px;
  cursor: grab;
}
.ts-note[data-dragging='true'] { opacity: 0.4; }

/* The only rule on the sheet is Pohja's own gold hairline, marking what
   came from Business Memory. It fades with the note, so an old note
   stops asking anything of you. */
.ts-ref {
  display: block;
  border-left: 1px solid var(--ts-gold);
  padding: 1px 0 1px 12px;
  margin: 0 0 9px;
  text-decoration: none;
}
.ts-ref .ts-title { display: block; font-family: 'Inter', sans-serif; font-size: 12.5px; line-height: 1.4; }
.ts-ref .ts-id { display: block; font-family: 'IBM Plex Mono', monospace; font-size: 9.5px; margin-top: 3px; }

/* §8.2 — Playfair italic for free text a person wrote. Handwriting was
   considered and rejected: a script face would say human twice. */
.ts-words {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-size: 14.5px;
  line-height: 1.75;
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
}
.ts-words[contenteditable='true']:focus { outline: none; }

.ts-files {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  color: var(--ts-mute);
  margin: 6px 0 0;
}
.ts-files span,
.ts-files button { display: block; }

/* §8.5 — minimal, and none at rest on a note. Two acts appear on hover,
   plus take it off. */
.ts-acts {
  display: flex;
  gap: 14px;
  margin-top: 7px;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.ts-note:hover .ts-acts,
.ts-note:focus-within .ts-acts { opacity: 1; }

.ts-act {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--ts-mute);
}
.ts-act:hover { color: var(--ts-gold); }
.ts-act:focus-visible { outline: 2px solid var(--ts-gold); outline-offset: 3px; }

/* The retention phrase is a statement, not an act. It borrowed .ts-act
   for the size and letter-spacing and inherited the hover with it, so
   it turned gold under the pointer — and gold in this system means the
   thing wants something from you. This one wants nothing: it says what
   happens whether you act or not. */
.ts-act[data-role='phrase'],
.ts-act[data-role='phrase']:hover { color: var(--ts-mute); cursor: default; }

/* §6.1 — an always-present write area. */
.ts-write {
  border-top: 1px solid var(--ts-rule);
  padding: 14px 26px 17px;
  background: var(--ts-paper);
}
.ts-input {
  width: 100%;
  border: 0;
  resize: none;
  background: none;
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-size: 14.5px;
  line-height: 1.75;
  color: #16191c;
  min-height: 24px;
  max-height: 140px;
}
.ts-input:focus { outline: none; }
.ts-input::placeholder { color: #a0a8b0; font-style: italic; }

.ts-foot { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; }
.ts-foot-acts { display: flex; gap: 14px; }

/* §5.3 — a private window destroys this silently, and a feature
   described as private invites exactly that instinct. It must say so on
   itself. */
.ts-warn {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--ts-gold);
  padding: 10px 22px 0;
}

/* §6.3 — the Pohja side is never a drop target. Not styled as one, not
   accepting one. It dims to mean AWAY, not INTO Pohja. */
body[data-ts-dragging='true'] .ts-away { opacity: 0.55; transition: opacity 0.15s ease; }

.ts-drop { box-shadow: inset 0 0 0 1px var(--ts-gold); }

.ts-undo {
  position: absolute;
  left: 26px;
  bottom: 78px;
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--ts-gold);
  background: none;
  border: 0;
  cursor: pointer;
}

.ts-send-menu {
  position: absolute;
  right: 26px;
  bottom: 68px;
  background: #ffffff;
  border: 1px solid var(--ts-rule);
  border-radius: 2px;
  box-shadow: 0 12px 32px rgba(22, 25, 28, 0.12);
  padding: 6px 0;
  min-width: 180px;
}
.ts-send-menu button {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 9px 16px;
  cursor: pointer;
  font-family: 'Inter', sans-serif;
  font-size: 12px;
  color: #434a52;
}
.ts-send-menu button:hover { color: var(--ts-gold); }
.ts-send-menu .ts-note-limit { font-size: 10px; color: var(--ts-mute); }

@media (max-width: 900px) {
  /* §9 §0.3 — desktop only. Not a reduced mobile surface: it is a
     browser-local store keyed to a device, so a phone would be a second
     unrelated surface and offering it would imply a continuity that does
     not exist. */
  .ts-root { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .ts-root, .ts-acts { transition-duration: 0.01ms !important; }
}

/* Where the surface is held, and the memory-only state. Added 12 August
   2026. Quiet by construction: this is a standing fact rather than
   something asking for attention, so it takes the muted ink and never
   the gold.

   Cleared below the name. .ts-tab is absolutely positioned at the top of
   the sheet, so a paragraph placed after it in the markup lands in the
   same space and prints over it — which is exactly what happened. */
.ts-eph {
  margin: 0;
  padding: 30px 20px 0;
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--ts-mute);
}
.ts-act[data-on="1"] {
  border-color: var(--ts-ink, #16191c);
  color: var(--ts-ink, #16191c);
  font-weight: 500;
}

/* The footer was built for two controls and a phrase. It now carries
   three controls, so on a 366px sheet "Keep nothing on this device" ran
   into "Clears by tomorrow". It wraps rather than collides, and the
   retention phrase sits on its own line beneath, which is where a
   standing fact belongs anyway. */
.ts-foot {
  flex-wrap: wrap;
  gap: 8px 14px;
  align-items: baseline;
}
.ts-foot-acts { flex-wrap: wrap; gap: 8px 14px; }
.ts-act[data-role='phrase'] { flex: 1 1 100%; }
