/* לוח משימות — board styling.
 *
 * The brief, in Ynon's words: Assistant, RTL, free notes you write INTO rather
 * than into a dialog, no shadows, thin black borders, high contrast.
 *
 * So: there is not a single box-shadow in this file. Every edge in the UI is a
 * hairline border, and every state that would normally be expressed with a
 * shadow (lifting a note, hovering a zone) is expressed with border weight,
 * fill, or scale instead. That is a real constraint and it drives the whole
 * look — the board reads as drawn rather than as floating.
 *
 * Colour is two tokens deep on purpose: ink and paper. Dark mode swaps them
 * rather than introducing a second palette, which is why contrast survives it.
 */

/* Assistant, self-hosted. Not Google's CDN: the board must not depend on a
   third party being reachable, and a font request from his phone should not
   leave the box. One variable file per subset covers every weight we use. */
@font-face {
  font-family: 'Assistant';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('/fonts/assistant-hebrew.woff2?v=1') format('woff2');
  unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face {
  font-family: 'Assistant';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('/fonts/assistant-latin-ext.woff2?v=1') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Assistant';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('/fonts/assistant-latin.woff2?v=1') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --ink: #0c0c0c;
  --paper: #f2f0e9;
  --card: #ffffff;
  --line: #0c0c0c;
  --soft: #6b6862;          /* the only mid tone; used for counts and hints */
  --grid: rgba(12, 12, 12, 0.055);
  --tint: #ecebe3;          /* zone fill on drag-over */
  --live: #0c0c0c;
  --warn-bg: #fdf3d2;
  --bad: #a41d10;
  --bad-bg: #fbe4e0;
  --ok: #17492c;
  --ok-bg: #dfeee3;
  --hair: 1px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ink: #f1efe8;
    --paper: #121210;
    --card: #1b1b18;
    --line: #f1efe8;
    --soft: #9c988f;
    --grid: rgba(241, 239, 232, 0.06);
    --tint: #262622;
    --live: #f1efe8;
    --warn-bg: #3a3218;
    --bad: #ff9c8c;
    --bad-bg: #3d1c16;
    --ok: #a9dcbb;
    --ok-bg: #17301f;
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;              /* only .scroll scrolls */
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: 'Assistant', -apple-system, 'SF Hebrew', system-ui, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.45;
  direction: rtl;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
}

/* ---------------- top bar ---------------- */

.bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  padding-top: calc(10px + env(safe-area-inset-top));
  background: var(--paper);
  border-bottom: var(--hair) solid var(--line);
}

.bar-title {
  flex: 1;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.bar-btn {
  font: inherit;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  background: transparent;
  border: var(--hair) solid var(--line);
  border-radius: 3px;
  padding: 6px 13px;
  min-height: 34px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.bar-btn:active { background: var(--tint); }
.bar-btn:disabled { opacity: 0.4; }

.bar-btn.primary {
  background: var(--ink);
  color: var(--paper);
  font-size: 20px;
  font-weight: 400;
  line-height: 1;
  padding: 0;
  width: 34px;
  display: grid;
  place-items: center;
}

.bar-btn.primary:active { background: var(--soft); }

/* ---------------- banner + toast ---------------- */

.banner {
  flex: none;
  padding: 9px 14px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.4;
  background: var(--warn-bg);
  color: var(--ink);
  border-bottom: var(--hair) solid var(--line);
}

.toast {
  position: fixed;
  left: 14px;
  right: 14px;
  bottom: calc(16px + env(safe-area-inset-bottom));
  z-index: 40;
  padding: 11px 14px;
  font-size: 13.5px;
  font-weight: 600;
  border: var(--hair) solid var(--line);
  border-radius: 3px;
  background: var(--bad-bg);
  color: var(--bad);
}

.toast.ok { background: var(--ok-bg); color: var(--ok); }

/* ---------------- board ---------------- */

.scroll {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 16px 0 calc(72px + env(safe-area-inset-bottom));
  /* Graph paper. This is what makes it read as a board rather than a list —
     it gives the free-floating notes something to sit ON. */
  background-image:
    repeating-linear-gradient(to bottom, var(--grid) 0 1px, transparent 1px 24px),
    repeating-linear-gradient(to right,  var(--grid) 0 1px, transparent 1px 24px);
}

.scroll.locked { overflow: hidden; }     /* while a note is in hand */

.stage { display: flex; justify-content: flex-start; }

.board {
  position: relative;
  transform-origin: top right;
}

#zones, #notes { position: absolute; inset: 0; }
#notes { pointer-events: none; }         /* only the notes themselves take input */
#notes > * { pointer-events: auto; }

/* ---------------- zones ---------------- */

.zone {
  position: absolute;
  border: var(--hair) solid var(--line);
  border-radius: 4px;
  background: transparent;
  transition: background-color 130ms ease, border-color 130ms ease;
}

/* The drop target while a note is in hand. Border doubles inward via an inset
   ring rather than growing the box, so nothing under it shifts by a pixel. */
.zone.hot {
  background: var(--tint);
  box-shadow: inset 0 0 0 1px var(--line);
}

.zone-title {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: 30px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  border-bottom: var(--hair) solid var(--line);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: -0.005em;
}

.zone-name {
  flex: 1;
  unicode-bidi: isolate;
  direction: rtl;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.zone-count {
  flex: none;
  min-width: 19px;
  height: 19px;
  padding: 0 5px;
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--soft);
  border: var(--hair) solid currentColor;
  border-radius: 10px;
  unicode-bidi: isolate;
}

/* ---------------- notes ---------------- */

.note {
  position: absolute;
  display: flex;
  align-items: flex-start;
  gap: 7px;
  padding: 9px 10px;
  background: var(--card);
  color: var(--ink);
  border: var(--hair) solid var(--line);
  border-radius: 3px;
  cursor: grab;
  /* The drag gesture IS a long press, so iOS must not answer it with the
     copy/lookup callout or a blue selection. Both are re-enabled while the
     note is actually being edited, below. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  /* Fixed height, not min-height. Notes are laid out on a fixed grid, so one
     that grew with its text would sit on top of the note below it — which is
     exactly what a long title did. The overflow is clamped away instead, which
     also matches the standing instruction: less text on a note, not more. */
  overflow: hidden;
  transition: transform 40ms linear, border-width 90ms ease, background-color 120ms ease;
}

.note-title {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.006em;
  overflow-wrap: anywhere;
  /* The note is resizable now, so the title fills whatever height he gave it
     rather than stopping at a fixed count of lines. The clamp is a large cap
     that only bites on an absurdly long title in a very tall note. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 24;
  overflow: hidden;
  /* Every title mixes Hebrew with Latin and digits ("CRM ימיש", "Base44").
     Isolate each one and force the base direction — dir="auto" reads the first
     strong character and flips lines like "CRM ימיש" the wrong way round. */
  unicode-bidi: isolate;
  direction: rtl;
  text-align: right;
  outline: none;
}

/* The done target. Its own hit area, so a tap here never starts an edit. */
.note-done {
  flex: none;
  width: 17px;
  height: 17px;
  margin-top: 1px;
  padding: 0;
  background: transparent;
  border: var(--hair) solid var(--line);
  border-radius: 50%;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.note-done:active { background: var(--ink); }

/* Picked up. No shadow — the note grows a heavier edge and a little scale, and
   the zone under it fills in. That reads as "in hand" without any depth. */
.note.lift {
  border-width: 2px;
  transform-origin: center;
  cursor: grabbing;
  z-index: 20;
  transition: none;
}

.note.snap { transition: transform 200ms cubic-bezier(0.2, 0.9, 0.25, 1); }
.note.busy { opacity: 0.55; }

.note.gone {
  transition: opacity 190ms ease, transform 190ms ease;
  opacity: 0;
  transform-origin: center;
}

/* Writing happens HERE, in the note. Not in a sheet, not in a modal.
   An open note grows past its slot and over its neighbours — it has to, or he
   would be typing into four clamped lines and unable to see the end of his own
   sentence. It is on top while open and back in its slot the moment it closes. */
.note.editing {
  border-width: 2px;
  background: var(--card);
  z-index: 30;
  height: auto !important;
  min-height: 92px;
  overflow: visible;
  cursor: text;
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

.note.editing .note-title {
  display: block;
  -webkit-line-clamp: none;
  overflow: visible;
  -webkit-user-select: text;
  user-select: text;
}

.note.editing .note-done { visibility: hidden; }

.note-title:empty::before {
  content: attr(data-placeholder);
  color: var(--soft);
  font-weight: 400;
}

/* ---------------- skeleton + empty ---------------- */

.skel {
  position: absolute;
  border: var(--hair) dashed var(--line);
  border-radius: 3px;
  opacity: 0.3;
  animation: pulse 1.25s ease-in-out infinite;
}

@keyframes pulse { 0%, 100% { opacity: 0.18; } 50% { opacity: 0.4; } }

.empty {
  padding: 40px 24px;
  text-align: center;
  color: var(--soft);
  font-size: 14px;
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}


/* ---------- resize grip ----------
   Bottom-left, which is where a right-to-left card ends. Drawn as two hairline
   strokes rather than a filled tab: the same ink-on-paper vocabulary as every
   other edge here, and it stays quiet until he goes for it. The hit area is
   larger than the mark, because a finger is wider than two lines. */

.note-grip {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 26px;
  height: 26px;
  cursor: nwse-resize;
  touch-action: none;
  -webkit-touch-callout: none;
}

.note-grip::before,
.note-grip::after {
  content: "";
  position: absolute;
  left: 5px;
  border-bottom: var(--hair) solid var(--soft);
  transform: rotate(45deg);
  transform-origin: left bottom;
  opacity: 0.75;
}
.note-grip::before { bottom: 6px; width: 9px; }
.note-grip::after  { bottom: 6px; width: 15px; left: 5px; opacity: 0.45; }

.note.sizing {
  z-index: 30;
  border-color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--ink);
}
.note.sizing .note-grip::before,
.note.sizing .note-grip::after { border-bottom-color: var(--ink); opacity: 1; }

/* While a note is open for writing the grip would only be in the way. */
.note.editing .note-grip { display: none; }

/* ---------- open canvas ----------
   The space around and between the zones is a real place to leave a note, so
   it is drawn as a surface rather than as a gap: the faint grid says "you may
   put something here", and it stops at nothing, which is the point. */

.board {
  background-image:
    linear-gradient(to right, var(--grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid) 1px, transparent 1px);
  background-size: 26px 26px;
}

/* A zone is a marking on that surface, not a container: it sits on the grid
   with its own paper fill so its contents read as grouped, while the canvas
   continues past its edges. */
.zone { background: var(--paper); }


/* ---------- the board scrolls in two directions now ---------- */
.scroll { overflow-x: auto; }

/* ---------- completed ----------
   A completed task is still a task. It stays legible and keeps its place; it
   just stops competing for attention. Ruled through, not greyed into a smudge,
   and its circle stays a live control because un-ticking is the same click. */
.note.done {
  background: transparent;
  border-style: dashed;
  color: var(--soft);
}
.note.done .note-title { text-decoration: line-through; text-decoration-thickness: 1px; }
.note.done .note-done { background: var(--ink); border-color: var(--ink); }
.note.done .note-grip::before,
.note.done .note-grip::after { opacity: 0.3; }

.bar-btn.on { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* ---------- his own groups ----------
   Deliberately not drawn like a zone. A zone is a Google list and is filled
   paper; a group is a box he drew, so it is an outline — dashed, transparent,
   and it never hides what is under it. That difference has to be visible at a
   glance, because dropping a note in one of them changes a task in Google and
   dropping it in the other does not. */

.group {
  position: absolute;
  border: var(--hair) dashed var(--line);
  border-radius: 4px;
  background: transparent;
}

.group-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 6px 0 4px;
  border-bottom: var(--hair) dashed var(--line);
  cursor: grab;
  touch-action: none;
  -webkit-touch-callout: none;
}

.group-title {
  flex: 1;
  min-width: 0;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: -0.006em;
  color: var(--ink);
  outline: none;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  unicode-bidi: isolate;
}
.group-title:empty::before { content: attr(data-placeholder); color: var(--soft); font-weight: 400; }
.group-title:focus { text-overflow: clip; }

.group-del {
  flex: none;
  width: 20px; height: 20px;
  padding: 0;
  font: inherit; font-size: 15px; line-height: 1;
  background: transparent;
  border: none;
  color: var(--soft);
  cursor: pointer;
}
.group-del:active { color: var(--ink); }

.group-grip {
  position: absolute;
  right: 0; bottom: 0;
  width: 26px; height: 26px;
  cursor: nwse-resize;
  touch-action: none;
}
.group-grip::before {
  content: "";
  position: absolute;
  right: 5px; bottom: 6px;
  width: 12px;
  border-bottom: var(--hair) solid var(--soft);
  transform: rotate(-45deg);
  transform-origin: right bottom;
}

.group.lift { border-style: solid; background: var(--tint); }
.group.sizing { border-style: solid; }

/* Dragging the empty canvas with a mouse. */
.scroll.panning { cursor: grabbing; }
.scroll.panning .note, .scroll.panning .group-head { cursor: grabbing; }


/* ---------- the scroll container is LTR on purpose ----------
   Measured, not assumed: inside an rtl document, scrollLeft runs from 0 at the
   RIGHT edge down to a negative number at the left. Setting it to +50 clamped
   it to 0, so every horizontal correction the zoom made was silently thrown
   away and the point under the fingers drifted 57px sideways while the
   vertical one stayed pinned.

   The container scrolls in ordinary left-to-right coordinates; the board
   inside it keeps direction: rtl, so every piece of Hebrew still reads the
   right way. Only the scrollbar arithmetic changes. */
.scroll { direction: ltr; }
.board { direction: rtl; }

/* ---------- why the board scales from its top-left ----------
   It was `top right`, which reads like the correct choice for a right-to-left
   board. It is not, once the board can zoom: the painted box then stops
   matching its layout box, and the scrollable area is computed from the layout
   box. Zoomed in, the board extends LEFT past anything the container can
   scroll to, and part of the canvas becomes unreachable — measured as a note
   whose centre sat at x = -47, off screen, un-grabbable.

   With `top left` the painted box starts exactly where the sizer starts and is
   exactly as wide as the sizer is made (boardW * SCALE), so what you can see
   and what you can scroll to are the same thing at every zoom level. Direction
   is unaffected: the board keeps `direction: rtl` and every line of Hebrew
   still reads the right way. */
.board { transform-origin: top left; }
