/* ══════════════════════════════════════════════════════════════════
   app.css — Happy Light Journal.

   Same warm-ink token set as the rest of the suite, so theme.js's
   [data-theme] switch drives this page the way it drives the arcade,
   the Pixel Studio and Triggers. Dark is the bare :root; light
   overrides only what actually changes.

   theme.js always stamps an explicit data-theme before first paint
   (resolving "auto" against the OS itself), which is why there is no
   prefers-color-scheme block here — a media query would be a second,
   competing source of truth.
   ══════════════════════════════════════════════════════════════════ */
:root{
  --bg:#0b0a0d; --bg-2:#16131a;
  --panel:rgba(29,25,34,.82); --panel-solid:#1d1922;
  --line:rgba(184,175,164,.20); --line-hot:rgba(245,158,11,.45);
  --ink:#f5f1ea; --ink-dim:#b8afa4; --ink-faint:#6b635a;
  --brand:#f59e0b; --brand-2:#a78bfa;
  --ok:#4ee8a5; --warn:#fbbf24; --bad:#f87171;
  --surf:rgba(43,37,51,.72);
  /* Tag and filter chips. A tint of the brand rather than a new hue,
     so a wall of tags does not compete with the prose. */
  --chip:rgba(245,158,11,.12); --chip-on:rgba(245,158,11,.20);
  --shadow:4px 4px 0 rgba(0,0,0,.45);
  /* Logo palette. Wordmark strokes are currentColor; only the bulb
     reads these, so one asset serves both grounds. */
  --logo-glow:1; --logo-glow-color:#f59e0b; --logo-bulb:#d9a441;
  --logo-glass-hi:#fffdf6; --logo-glass-lo:#f8e3b6; --logo-face:#8a6a3b;
  --font:"Inter Variable","Inter",ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  /* A measured reading column for the preview. Prose set the full width
     of a desktop pane is genuinely harder to read. */
  --measure:34rem;
  --r:12px;
}
:root[data-theme="light"]{
  --bg:#faf8f4; --bg-2:#f1ece2;
  --panel:rgba(255,253,247,.92); --panel-solid:#fffdf7;
  --line:rgba(90,74,54,.22); --line-hot:rgba(180,83,9,.42);
  --ink:#241f18; --ink-dim:#5b5145; --ink-faint:#7d7264;
  --brand:#b45309; --brand-2:#6d28d9;
  --ok:#047857; --warn:#8c6510; --bad:#b91c1c;
  --surf:rgba(241,236,226,.80);
  --chip:rgba(180,83,9,.10); --chip-on:rgba(180,83,9,.18);
  --shadow:4px 4px 0 rgba(90,74,54,.22);
  /* Paper turns the bloom to haze — drop the glow, deepen the bulb. */
  --logo-glow:0; --logo-bulb:#a86f18;
  --logo-glass-hi:#fffaec; --logo-glass-lo:#f2d79c; --logo-face:#6b4d22;
}

*{box-sizing:border-box}
input[type=checkbox]{accent-color:var(--brand)}
[hidden]{display:none !important}

html{color-scheme:dark;height:100%}
:root[data-theme="light"]{color-scheme:light}

body{
  margin:0;background:var(--bg);color:var(--ink);
  font-family:var(--font);font-size:15px;line-height:1.55;
  -webkit-font-smoothing:antialiased;
  /* The app is a fixed frame with independently scrolling panes, so the
     page itself never scrolls. A flex column rather than a height
     calculation: the alert changes
     height (they wrap at narrow widths, and the alert comes and goes),
     and subtracting guessed constants clipped the sidebar footer.
     100dvh, not vh, so a collapsing mobile URL bar leaves no dead strip. */
  height:var(--app-h,100dvh);     /* --app-h: iOS soft keyboard, see setupViewportFit */
  display:flex;flex-direction:column;
  overflow:hidden;
}
.jr-alert{flex:none}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

a{color:var(--brand)}
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,
textarea:focus-visible,summary:focus-visible{
  outline:2px solid var(--brand);outline-offset:2px;border-radius:4px;
}

.skip{position:absolute;left:-9999px;top:0;background:var(--panel-solid);
  color:var(--ink);padding:.6rem .9rem;z-index:80;border-radius:0 0 var(--r) 0}
.skip:focus{left:0}

/* ── brand lockup ──
   inline-flex + column is what stacks the subtitle under the mark. It
   must stay inline-flex: the lockup is taller than its line box (the
   viewBox reserves headroom for the bulb), so as a plain inline element
   it escapes and the sticky bar clips the bulb. */
.wordmark{font-weight:700;letter-spacing:-.03em;line-height:1;
  display:inline-flex;flex-direction:column;align-items:center;gap:.3rem}
.wordmark.small{font-size:1.2rem}
.wordmark .hl-lockup{height:2em;width:auto;display:inline-block;
  color:var(--ink);flex:none}
.wm-b{color:var(--ink-dim);font-size:max(.62rem,.16em);font-weight:700;
  letter-spacing:.26em;text-indent:.26em;text-transform:uppercase;line-height:1}

/* ── brand ──
   At the start of the tab bar (see "the tab bar" below). */
.jr-home{text-decoration:none;flex:none;align-items:center}

/* ── where the notes live: pill + toggletip ── */
.jr-store{appearance:none;font:inherit;display:inline-flex;align-items:center;gap:.4rem;
  min-width:0;flex:0 1 auto;padding:.22rem .28rem .22rem .6rem;border-radius:999px;
  border:1px solid var(--line);background:var(--surf);color:var(--ink-dim);
  font-size:.74rem;line-height:1.2;cursor:pointer;white-space:nowrap}
.jr-store:hover{border-color:var(--line-hot);color:var(--ink)}
.jr-store:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.jr-store[aria-expanded="true"]{border-color:var(--brand);color:var(--ink)}
.jr-store-dot{width:.5rem;height:.5rem;border-radius:50%;flex:none;background:var(--warn)}
.jr-store[data-tone="ok"] .jr-store-dot{background:var(--ok)}
.jr-store-short,.jr-store-tiny{overflow:hidden;text-overflow:ellipsis;min-width:0}
.jr-store-tiny{display:none}
.jr-store-i{flex:none;width:1.05rem;height:1.05rem;border-radius:50%;display:grid;place-items:center;
  font:italic 700 .68rem/1 Georgia,"Times New Roman",serif;border:1px solid currentColor;opacity:.75}

/* Fixed, and outside the panel in the DOM: a scrolling or transformed
   ancestor (the phone drawer is both) would clip it. Positioned under
   whichever button opened it, from script. Visible is the resting state; the
   animation only eases into it, so reduced motion leaves it present. */
.jr-store-tip{position:fixed;left:.5rem;top:3.5rem;z-index:65;
  width:min(24rem,calc(100vw - 1rem));max-height:calc(var(--app-h,100dvh) - 4.5rem);overflow-y:auto;
  padding:.8rem .9rem .85rem;border:1px solid var(--line);border-radius:.7rem;
  background:var(--panel-solid);box-shadow:var(--shadow);color:var(--ink);
  font-size:.8rem;line-height:1.5;animation:jr-tip-in .14s ease both}
.jr-store-tip:focus{outline:none}
.jr-store-tip:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.jr-store-title{margin:0 0 .35rem;font-weight:700;font-size:.85rem}
.jr-store-lines p{margin:0 0 .45rem;color:var(--ink-dim)}
.jr-store-lines p.jr-store-persisted{color:var(--ink)}
.jr-store-acts{display:flex;flex-wrap:wrap;gap:.35rem;margin-top:.55rem}

.jr-btn{appearance:none;font:inherit;font-size:.82rem;cursor:pointer;
  color:var(--ink);background:var(--surf);border:1px solid var(--line);
  border-radius:999px;padding:.32rem .8rem}
.jr-btn:hover{border-color:var(--line-hot)}

.jr-seg{display:inline-flex;border:1px solid var(--line);border-radius:999px;
  overflow:hidden;background:var(--surf)}
.jr-seg button{appearance:none;background:none;border:0;color:var(--ink-dim);
  font:inherit;font-size:.78rem;padding:.3rem .7rem;cursor:pointer}
.jr-seg button.on{background:var(--brand);color:#1a1206;font-weight:700}
:root[data-theme="light"] .jr-seg button.on{color:#fff}

/* ── bar menu ──
   Same <details>/<summary> pattern as portal, the arcade, the pixel
   editor and triggers: keyboard-operable with no custom widget; script
   only adds Escape and click-away. */
.hl-menu{position:relative}
.hl-menu-summary{display:flex;align-items:center;gap:.45rem;cursor:pointer;list-style:none;
  padding:.3rem .7rem;border:1px solid var(--line);border-radius:999px;background:var(--surf);
  color:var(--ink-dim);font-size:.78rem;user-select:none}
.hl-menu-summary::-webkit-details-marker{display:none}
.hl-menu-summary:hover{border-color:var(--line-hot);color:var(--ink)}
.hl-menu-bars{width:.85rem;height:.7rem;flex:none;
  border-top:2px solid currentColor;border-bottom:2px solid currentColor;position:relative}
.hl-menu-bars::after{content:"";position:absolute;left:0;right:0;top:calc(50% - 1px);
  border-top:2px solid currentColor}
.hl-menu-panel{position:absolute;right:0;top:calc(100% + .35rem);z-index:60;
  min-width:15rem;display:flex;flex-direction:column;padding:.3rem;
  border:1px solid var(--line);border-radius:.6rem;
  background:var(--panel-solid);box-shadow:var(--shadow);
  /* The page never scrolls, so a menu taller than the space below the
     header was simply cut off on a phone (Sync and the account links
     sat below the screen at 390x844). wireMenu sets the exact height on
     open; this is the fallback. */
  max-height:calc(100dvh - 9rem);overflow-y:auto;overscroll-behavior:contain}
/* Without this a capped flex column SHRINKS its children to fit instead
   of scrolling — the theme switch collapsed to 2px and became unclickable. */
.hl-menu-panel > *{flex:none}
.hl-menu-head{margin:.45rem .55rem .2rem;font-size:.62rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink-faint)}
.hl-menu-head:first-child{margin-top:.2rem}
.hl-menu-item{appearance:none;background:none;border:0;cursor:pointer;font:inherit;
  font-size:.85rem;color:var(--ink);text-align:left;text-decoration:none;
  padding:.45rem .55rem;border-radius:.4rem}
.hl-menu-item:hover{background:var(--line)}
.hl-menu-item:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}
.hl-menu-seg{margin:.15rem .55rem .3rem;align-self:flex-start}
/* A label inside a group ("Export" under This note): quieter than a head,
   with its items indented under it so they read as one cluster. */
.hl-menu-subhead{margin:.3rem .55rem .1rem;font-size:.7rem;color:var(--ink-faint)}
.hl-menu-item.hl-menu-sub{padding-left:1.1rem}
/* Folded groups. The summary looks like a section head that can open, with
   a caret that turns; the body is its own column so the items stack the
   way they do directly in the panel. */
.hl-menu-group{display:flex;flex-direction:column}
.hl-menu-group-sum{list-style:none;cursor:pointer;display:flex;align-items:center;gap:.4rem;
  margin:.25rem 0 0;padding:.4rem .55rem;border-radius:.4rem;
  font-size:.62rem;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-faint);user-select:none}
.hl-menu-group-sum::-webkit-details-marker{display:none}
.hl-menu-group-sum::before{content:"";flex:none;width:.4rem;height:.4rem;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:rotate(-45deg);transition:transform .15s ease;margin-right:.1rem}
.hl-menu-group[open] > .hl-menu-group-sum::before{transform:rotate(45deg)}
.hl-menu-group-sum:hover{background:var(--line);color:var(--ink-dim)}
.hl-menu-group-sum:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}
.hl-menu-group-body{display:flex;flex-direction:column}
.hl-menu-group-body > *{flex:none}
@media (prefers-reduced-motion:reduce){ .hl-menu-group-sum::before{transition:none} }

/* Share on the bar. The dot is only drawn when the open note is being
   edited together (coedit-ui.js sets data-coedit), coloured like the pill. */
.jr-share{display:inline-flex;align-items:center;gap:.35rem}
.jr-share-dot{display:none;width:.5rem;height:.5rem;border-radius:50%;flex:none;background:var(--ink-faint)}
.jr-share[data-coedit] .jr-share-dot{display:inline-block}
.jr-share[data-coedit="live"] .jr-share-dot{background:var(--ok)}
.jr-share[data-coedit="offline"] .jr-share-dot,
.jr-share[data-coedit="reconnecting"] .jr-share-dot{background:var(--warn)}

/* ── notices ── */

.jr-alert{margin:0;padding:.6rem .9rem;font-size:.84rem;cursor:pointer;
  border-bottom:1px solid var(--line)}
.jr-alert.ok{background:color-mix(in srgb,var(--ok) 16%,var(--bg-2));color:var(--ink)}
.jr-alert.warn{background:color-mix(in srgb,var(--warn) 18%,var(--bg-2));color:var(--ink)}
.jr-alert.bad{background:color-mix(in srgb,var(--bad) 20%,var(--bg-2));color:var(--ink)}

/* Undo toast: bottom-anchored so it never fights the alert banner for
   the same strip of chrome. */
.jr-toast{
  position:fixed;left:50%;bottom:1.2rem;transform:translateX(-50%);
  z-index:80;display:flex;align-items:center;gap:.9rem;
  background:var(--panel-solid);border:1px solid var(--line);
  border-radius:.6rem;box-shadow:var(--shadow);
  padding:.6rem .7rem .6rem 1rem;font-size:.86rem;color:var(--ink);
}
.jr-toast button{
  background:var(--chip);border:1px solid var(--line-hot);border-radius:.4rem;
  color:var(--brand);font:inherit;font-weight:600;padding:.3rem .7rem;cursor:pointer;
}
.jr-toast button:hover{background:var(--chip-on)}

/* ── frame ──
   A fixed shell: the tab bar, then ONE panel — the Notes tab (picker)
   or the editor — filling the rest. There is no sidebar any more, so the
   editor always has the full width. */
.jr-main{
  display:flex;flex-direction:column;
  flex:1;
  min-height:0;      /* without this a flex child refuses to shrink */
  min-width:0;
}
.jr-main > .jr-side,.jr-main > .jr-workarea{flex:1;min-height:0}

/* Above the phone width the wordmark sits at the start of the tab bar. */
@media (min-width:769px){ .jr-tabbar .jr-home{display:inline-flex} }

/* "This note" menu items have no note to act on from the Notes tab. */
.jr-main[data-tab="notes"] [data-note-only]{display:none}

/* ── the tab bar ──
   Tabs sit on the bar's bottom edge and the showing one opens into the
   panel below (same ground, no line between), like paper tabs. */
.jr-tabbar{flex:none;display:flex;align-items:center;gap:.35rem;min-width:0;
  padding:.3rem .6rem 0;background:var(--bg-2);border-bottom:1px solid var(--line);
  position:relative;z-index:31}
.jr-tabbar > :not(.jr-tabs){margin-bottom:.3rem}
.jr-tabbar .jr-home{margin-right:.2rem}
.jr-tabbar .wordmark.small{font-size:.78rem;gap:.2rem}
.jr-tabs{flex:0 1 auto;min-width:0;align-self:stretch;display:flex;align-items:flex-end;gap:.15rem;
  overflow-x:auto;overflow-y:hidden;scrollbar-width:none;overscroll-behavior-x:contain}
.jr-tabs::-webkit-scrollbar{display:none}
.jr-tab{flex:0 1 auto;position:relative;display:inline-flex;align-items:center;gap:.35rem;
  min-width:6.5rem;max-width:15rem;height:2.25rem;padding:0 .3rem 0 .8rem;margin-bottom:-1px;
  border:1px solid transparent;border-bottom:0;border-radius:.65rem .65rem 0 0;
  background:transparent;color:var(--ink-dim);font:inherit;font-size:.82rem;cursor:pointer;
  -webkit-user-select:none;user-select:none}
.jr-tab:hover{background:var(--surf);color:var(--ink)}
.jr-tab.on{background:var(--bg);color:var(--ink);border-color:var(--line);font-weight:600}
.jr-tab:focus-visible{outline:2px solid var(--brand);outline-offset:-3px}
.jr-tab.dragging{opacity:.45}
.jr-tab-notes{flex:none;min-width:0;padding:0 .8rem;gap:.45rem}
.jr-tab-notes.on{color:var(--brand)}
.jr-tab-ico{width:1rem;height:1rem;flex:none}
.jr-tab-n{font-size:.7rem;font-weight:400;color:var(--ink-faint);font-variant-numeric:tabular-nums}
.jr-tab-title{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Unsaved typing: a dot, until the save lands (about half a second). */
.jr-tab-dot{display:none;width:.45rem;height:.45rem;border-radius:50%;background:var(--brand);flex:none}
.jr-tab.dirty .jr-tab-dot{display:inline-block}
.jr-tab-x{flex:none;display:grid;place-items:center;width:1.45rem;height:1.45rem;
  border:0;border-radius:.4rem;background:transparent;color:var(--ink-faint);
  font:inherit;font-size:1rem;line-height:1;cursor:pointer;opacity:0}
.jr-tab:hover .jr-tab-x,.jr-tab.on .jr-tab-x,.jr-tab-x:focus-visible{opacity:1}
.jr-tab-x:hover{background:var(--line);color:var(--ink)}
@media (hover:none){ .jr-tab-x{opacity:1} }

.jr-tabbar-btn{appearance:none;flex:none;display:inline-flex;align-items:center;justify-content:center;gap:.4rem;
  min-width:2rem;height:2rem;padding:0 .5rem;border:1px solid transparent;border-radius:999px;
  background:transparent;color:var(--ink-dim);font:inherit;font-size:.8rem;cursor:pointer}
.jr-tabbar-btn:hover{background:var(--surf);color:var(--ink)}
.jr-tabbar-btn:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}
.jr-tabbar-end{flex:none;display:flex;align-items:center;gap:.35rem;min-width:0;margin-left:auto}
.jr-tabbar-end .hl-me{max-width:10rem}
.jr-tabbar .hl-menu[open] > .jr-menu-btn{background:var(--chip-on);color:var(--brand)}
.jr-tabbar .hl-menu-word{display:none}
.jr-tabbar .hl-menu-panel{width:min(20rem,calc(100vw - 1rem))}
@media (min-width:1100px){ .jr-tabbar .hl-menu-word{display:inline} }
@media (max-width:1100px){
  .jr-tabbar .jr-store-short{display:none}
  .jr-tabbar .jr-store-tiny{display:inline}
}

/* ── the Notes tab: the picker ──
   The whole panel scrolls (not just the list), so the search bar can
   stick to the top and the content can be centred in a measure without
   putting the scrollbar in the middle of the screen. */
.jr-side{display:flex;flex-direction:column;min-height:0;min-width:0;background:var(--bg);
  overflow-y:auto;overscroll-behavior:contain}
.jr-side > *{flex:none;width:100%;max-width:74rem;margin-left:auto;margin-right:auto}
.jr-side-top{position:sticky;top:0;z-index:2;background:var(--bg);
  padding:.75rem clamp(.75rem,3vw,2rem) .5rem;
  display:flex;flex-wrap:wrap;align-items:center;gap:.4rem}
.jr-search{flex:1 1 14rem;min-width:0;width:auto;font:inherit;font-size:.9rem;color:var(--ink);
  background:var(--panel-solid);border:1px solid var(--line);
  border-radius:999px;padding:.45rem .95rem}
.jr-search::placeholder{color:var(--ink-faint)}
.jr-viewmode button{display:inline-flex;align-items:center;gap:.35rem;padding:.32rem .65rem}
.jr-viewmode svg{width:.95rem;height:.95rem;flex:none}
.jr-viewmode button:not(.on){color:var(--ink-dim)}

.jr-filter{padding:0 clamp(.75rem,3vw,2rem) .55rem}
.jr-filter .jr-tags{padding:0}

/* Both views share one list element; data-view picks the layout. */
.jr-list{list-style:none;margin:0 auto;padding:.2rem clamp(.75rem,3vw,2rem) 1.5rem}
.jr-item{position:relative;display:flex;align-items:stretch;gap:.2rem;min-width:0}
.jr-item-open{appearance:none;background:none;border:0;cursor:pointer;font:inherit;
  color:var(--ink);text-align:left;flex:1;min-width:0;border-radius:inherit}
.jr-item-open:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}
.jr-item-title{font-weight:650;font-size:.92rem;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.jr-item-prev{font-size:.8rem;color:var(--ink-dim);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.jr-item-foot{display:flex;flex-wrap:wrap;align-items:center;gap:.3rem;min-width:0}
.jr-item-when{font-size:.7rem;color:var(--ink-faint);letter-spacing:.03em;white-space:nowrap}
.jr-item-tag{font-size:.7rem;color:var(--brand);background:var(--chip);border-radius:999px;
  padding:.05rem .45rem;white-space:nowrap;max-width:12rem;overflow:hidden;text-overflow:ellipsis}
.jr-item-more{color:var(--ink-dim);background:var(--surf)}
.jr-item-del{appearance:none;background:none;border:0;cursor:pointer;
  color:var(--ink-faint);font-size:1.1rem;line-height:1;padding:0 .5rem;
  border-radius:.4rem;opacity:0}
.jr-item:hover .jr-item-del,.jr-item-del:focus-visible{opacity:1}
.jr-item-del:hover{color:var(--bad)}
@media (hover:none){ .jr-item-del{opacity:1} }

/* Cards: a grid of note tiles with the opening lines showing. */
.jr-list[data-view="cards"]{display:grid;grid-template-columns:repeat(auto-fill,minmax(15.5rem,1fr));gap:.75rem;align-content:start}
.jr-list[data-view="cards"] .jr-item{flex-direction:column;min-height:9rem;
  border:1px solid var(--line);border-radius:var(--r);background:var(--panel-solid)}
.jr-list[data-view="cards"] .jr-item:hover{border-color:var(--line-hot)}
.jr-list[data-view="cards"] .jr-item-open{display:flex;flex-direction:column;gap:.35rem;padding:.85rem .95rem .8rem}
.jr-list[data-view="cards"] .jr-item-title{white-space:normal;padding-right:1.4rem;
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical}
.jr-list[data-view="cards"] .jr-item-prev{flex:1;white-space:normal;line-height:1.45;
  display:-webkit-box;-webkit-line-clamp:3;line-clamp:3;-webkit-box-orient:vertical}
.jr-list[data-view="cards"] .jr-item-del{position:absolute;top:.4rem;right:.35rem;padding:.25rem .45rem}
.jr-list[data-view="cards"] .jr-item-check{position:absolute;top:.95rem;left:.85rem;margin:0;z-index:1}
.jr-list[data-view="cards"].selecting .jr-item-open{padding-left:2.4rem}
.jr-list[data-view="cards"] .jr-item.open{border-color:color-mix(in srgb,var(--brand) 45%,var(--line))}

/* List: one row per note — title, opening line, tags and age. */
.jr-list[data-view="list"] .jr-item{border-bottom:1px solid var(--line)}
.jr-list[data-view="list"] .jr-item:hover{background:var(--surf)}
.jr-list[data-view="list"] .jr-item-open{display:grid;align-items:baseline;gap:.15rem 1rem;
  grid-template-columns:minmax(9rem,18rem) minmax(0,1fr) auto;padding:.6rem .55rem}
.jr-list[data-view="list"] .jr-item-foot{flex-wrap:nowrap;justify-content:flex-end}
.jr-list[data-view="list"] .jr-item-check{align-self:center;margin:0 0 0 .45rem}
.jr-list[data-view="list"] .jr-item.open{box-shadow:inset 2px 0 0 var(--brand)}
@media (max-width:640px){
  .jr-list[data-view="list"] .jr-item-open{grid-template-columns:minmax(0,1fr)}
  .jr-list[data-view="list"] .jr-item-foot{justify-content:flex-start;flex-wrap:wrap}
}

.jr-list-empty{margin:0 auto;padding:1.5rem clamp(.75rem,3vw,2rem);font-size:.86rem;color:var(--ink-faint)}

.jr-side-foot{margin-top:auto;padding:.6rem clamp(.75rem,3vw,2rem) .8rem;
  display:flex;flex-wrap:wrap;gap:.2rem .8rem;font-size:.72rem;color:var(--ink-faint)}
.jr-count{font-weight:600;color:var(--ink-dim)}
.jr-usage{font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
.jr-usage.warn{color:var(--warn);font-weight:600}

/* ── work area ──
   data-view drives which panes exist. Using grid-template-columns
   rather than display:none keeps the textarea's scroll position and
   undo history intact across a view switch. */
.jr-workarea{display:flex;flex-direction:column;min-width:0;min-height:0}
.jr-work{display:grid;min-width:0;min-height:0;flex:1}
.jr-work[data-view="split"]{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
.jr-work[data-view="edit"]{grid-template-columns:minmax(0,1fr)}
.jr-work[data-view="read"]{grid-template-columns:minmax(0,1fr)}
.jr-work[data-view="edit"] .jr-pane-read{display:none}
.jr-work[data-view="read"] .jr-pane-edit{display:none}

.jr-pane{min-width:0;min-height:0;display:flex;overflow:hidden}
.jr-pane-edit{border-right:1px solid var(--line)}
.jr-work[data-view="edit"] .jr-pane-edit{border-right:0}

.jr-editor{
  flex:1;min-width:0;width:100%;resize:none;
  font-family:var(--mono);font-size:14px;line-height:1.7;
  color:var(--ink);background:var(--bg);border:0;outline-offset:-3px;
  padding:1rem clamp(.8rem,2.5vw,1.6rem) 6rem;
  overflow-y:auto;
  /* When typing moves the caret, the browser scrolls just enough to show
     it — flush against the bottom edge. This keeps the caret line ~4rem
     clear of that edge instead (measured: from 5px clipped to 59px of
     room at the end of a long note). */
  scroll-padding-block:1rem 4rem;
  tab-size:2;
}
.jr-editor::placeholder{color:var(--ink-faint)}

.jr-pane-read{overflow-y:auto;flex-direction:column}
.jr-pane-read > #preview{flex:none}
#preview{padding:1rem clamp(.8rem,2.5vw,1.6rem) 6rem;max-width:var(--measure);
  width:100%;margin:0 auto}

/* ── drop overlay ── */
.jr-drop{position:fixed;inset:0;z-index:70;display:grid;place-items:center;
  background:color-mix(in srgb,var(--bg) 78%,transparent);
  backdrop-filter:blur(2px);pointer-events:none}
.jr-drop span{border:2px dashed var(--brand);border-radius:var(--r);
  padding:1.2rem 1.6rem;font-weight:600;color:var(--ink);
  background:var(--panel-solid);text-align:center;max-width:min(90vw,28rem)}
.jr-drop code{font-family:var(--mono);font-size:.9em}

/* ══════════════════════════════════════════════════════════════════
   RENDERED MARKDOWN
   ══════════════════════════════════════════════════════════════════ */

.md{overflow-wrap:break-word}
.md > :first-child{margin-top:0}
.md > :last-child{margin-bottom:0}

.md h1,.md h2,.md h3,.md h4,.md h5,.md h6{
  line-height:1.25;margin:1.6em 0 .5em;font-weight:700;letter-spacing:-.01em}
.md h1{font-size:1.7rem}
.md h2{font-size:1.35rem;padding-bottom:.25rem;border-bottom:1px solid var(--line)}
.md h3{font-size:1.12rem}
.md h4{font-size:1rem}
.md h5,.md h6{font-size:.9rem;color:var(--ink-dim);text-transform:uppercase;letter-spacing:.08em}

.md p{margin:0 0 .9em}
.md strong{font-weight:700;color:var(--ink)}
.md em{font-style:italic}
.md del{color:var(--ink-faint)}

.md hr{border:0;border-top:1px solid var(--line);margin:1.8em 0}

.md ul,.md ol{margin:0 0 .9em;padding-left:1.4em}
.md li{margin:.2em 0}
.md .md-loose > li{margin:.6em 0}
/* Only the task items drop their marker. Putting list-style:none on the
   whole <ul> stripped the bullets from plain siblings in a mixed list —
   visible on the welcome note, where "Bullet lists, nested:" lost its
   bullet because two items further down were checkboxes. */
.md li.md-task{list-style:none;display:flex;gap:.5em;align-items:flex-start}
.md .md-tasklist{padding-left:1.15em}
.md li.md-task > input{margin-top:.35em;flex:none}
/* Everything after the checkbox lives in one block wrapper, so a nested
   list stacks BELOW the row's text instead of becoming a third flex item
   beside it. min-width:0 lets a long word or URL wrap rather than push
   the row wide — a flex item's default min-width:auto refuses to shrink. */
.md li.md-task > .md-task-body{flex:1 1 auto;min-width:0}
.md li.md-task > .md-task-body > :last-child{margin-bottom:0}

.md blockquote{margin:0 0 .9em;padding:.1em 0 .1em 1em;
  border-left:3px solid var(--brand);color:var(--ink-dim)}
.md blockquote > :last-child{margin-bottom:0}

.md code{font-family:var(--mono);font-size:.88em;
  background:var(--surf);border:1px solid var(--line);
  border-radius:.3em;padding:.1em .35em}
.md pre{margin:0 0 1em;padding:.8rem 1rem;overflow-x:auto;
  background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r)}
.md pre code{background:none;border:0;padding:0;font-size:.85em;line-height:1.6}
/* The language label, from the fence's info string. */
.md pre[data-lang]{position:relative;padding-top:1.5rem}
.md pre[data-lang]::before{content:attr(data-lang);position:absolute;top:.3rem;right:.6rem;
  font-size:.62rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-faint)}

/* A wide table scrolls inside its own box — the page never does. */
.md-table-wrap{overflow-x:auto;margin:0 0 1em;
  border:1px solid var(--line);border-radius:var(--r)}
.md table{border-collapse:collapse;width:100%;font-size:.9rem}
.md th,.md td{padding:.45rem .7rem;border-bottom:1px solid var(--line);text-align:left}
.md th{background:var(--surf);font-weight:700;white-space:nowrap}
/* Column alignment from the table's delimiter row. Classes rather than
   inline styles, so the CSP needs no 'unsafe-inline' for style-src. */
.md .md-al-left{text-align:left}
.md .md-al-center{text-align:center}
.md .md-al-right{text-align:right}
.md tbody tr:last-child td{border-bottom:0}

/* ── embedded media ── */
.md-img,.md-video{max-width:100%;height:auto;display:block;
  border-radius:var(--r);border:1px solid var(--line);margin:.4em 0}
.md-audio{margin:.6em 0;display:grid;gap:.25rem}
.md-audio audio{width:100%;max-width:100%}
.md-audio figcaption{font-size:.75rem;color:var(--ink-faint)}

.md-media-loading{display:inline-block;font-size:.8rem;color:var(--ink-faint);
  background:var(--surf);border:1px dashed var(--line);
  border-radius:.4em;padding:.2em .5em}

/* A reference whose blob is gone — said plainly rather than shown as a
   broken image icon. */
.md-missing{display:inline-block;font-size:.8rem;color:var(--warn);
  background:color-mix(in srgb,var(--warn) 12%,transparent);
  border:1px dashed var(--warn);border-radius:.4em;padding:.2em .5em}

/* A destination the sanitiser refused. Shown, not silently dropped. */
.md-blocked{color:var(--ink-dim);text-decoration:line-through wavy var(--bad)}
.md-blocked-tag{margin-left:.35em;font-size:.68rem;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;text-decoration:none;
  color:var(--bad);border:1px solid var(--bad);border-radius:.3em;padding:0 .3em;
  cursor:help}

/* A [[note link]]. Solid underline for a note that exists; dashed and
   muted for one that does not yet (clicking offers to create it); a
   dotted underline for a title several notes share. Never colour alone:
   the underline style carries the state too. */
.md-notelink{color:var(--brand);text-decoration:underline;text-decoration-thickness:1px;
  text-underline-offset:.18em;cursor:pointer;border-radius:3px}
.md-notelink:hover{text-decoration-thickness:2px}
.md-notelink:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.md-notelink.unresolved{color:var(--ink-dim);text-decoration-style:dashed;
  text-decoration-color:var(--ink-faint)}
.md-notelink.ambiguous{text-decoration-style:dotted}
.md-notelink.ambiguous::after{content:"²";font-size:.7em;vertical-align:super;
  margin-left:.05em;color:var(--ink-faint)}

/* ══════════════════════════════════════════════════════════════════
   NARROW
   Below this width "split" cannot honestly show two columns, so the
   panes stack and each gets its own scroll. The user's chosen view is
   not silently changed — the layout adapts to it.
   ══════════════════════════════════════════════════════════════════ */
@media (max-width:860px){
  .jr-work[data-view="split"]{
    grid-template-columns:minmax(0,1fr);
    grid-template-rows:minmax(8rem,1fr) minmax(8rem,1fr);
  }
  .jr-work[data-view="split"] .jr-pane-edit{
    border-right:0;border-bottom:1px solid var(--line);
  }
  #preview{max-width:none}
}


/* Someone who asked for less motion gets no transitions from us. */
@media (prefers-reduced-motion:reduce){
  *{transition:none !important;animation:none !important}
}


/* ══════════════════════════════════════════════════════════════════
   Tags, folders, and the quick-find palette.
   ══════════════════════════════════════════════════════════════════ */

/* ── tag chips, in the rendered note ─────────────────────────────── */

.md-tag{
  display:inline-block;
  padding:.05em .45em;
  border:1px solid var(--line);
  border-radius:999px;
  background:var(--chip);
  color:var(--brand);
  font:inherit;
  font-size:.92em;
  line-height:1.45;
  cursor:pointer;
  text-decoration:none;
}
button.md-tag{font-family:inherit}
.md-tag:hover,.md-tag:focus-visible{
  border-color:var(--brand);
  background:var(--chip-on);
}

/* ── the scope banner: what the list is filtered to ──────────────── */

.jr-scope{
  display:flex;align-items:center;gap:.5rem;
  padding:.4rem .7rem;
  border:1px solid var(--line-hot);border-radius:.6rem;
  background:var(--chip);
  font-size:.8rem;
}
/* The banners in the Notes tab sit inside the same gutters as the list. */
.jr-side > .jr-scope,.jr-side > .jr-selbar{
  width:calc(100% - 2 * clamp(.75rem,3vw,2rem));max-width:calc(74rem - 2 * clamp(.75rem,3vw,2rem));
  margin:0 auto .6rem;border-radius:.6rem}
.jr-scope-what{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink)}
.jr-scope-clear{
  flex:none;padding:.15rem .5rem;
  border:1px solid var(--line);border-radius:999px;
  background:transparent;color:var(--ink-dim);
  font:inherit;font-size:.74rem;cursor:pointer;
}
.jr-scope-clear:hover{border-color:var(--brand);color:var(--brand)}

/* ── tag chips ──────────────────────────────────────────────────── */

.jr-tags{display:flex;flex-wrap:wrap;gap:.35rem}
.jr-tag{
  padding:.2rem .6rem;
  border:1px solid var(--line);border-radius:999px;
  background:transparent;color:var(--ink-dim);
  font:inherit;font-size:.74rem;cursor:pointer;
}
.jr-tag:hover{border-color:var(--brand);color:var(--brand)}
.jr-tag.on{border-color:var(--brand);background:var(--chip-on);color:var(--brand)}
.jr-tag-n{opacity:.6;margin-left:.2rem;font-variant-numeric:tabular-nums}

/* ── the Find button ─────────────────────────────────────────────── */

.jr-find{display:inline-flex;align-items:center;gap:.35rem}
.jr-kbd{
  padding:0 .3rem;
  border:1px solid var(--line);border-radius:4px;
  background:var(--surf);
  font-family:inherit;font-size:.72em;color:var(--ink-dim);
}

/* ══════════════════════════════════════════════════════════════════
   Quick find.

   The OPEN state is the resting style: `.qf` and `.qf-panel` carry no
   opacity or transform of their own, and the keyframes below only
   animate *into* that state with `fill-mode: both`.

   That ordering is deliberate. The global reduced-motion rule in this
   file switches `animation` off outright, so anything that depended on
   an animation to reach its visible state would stay invisible — a
   palette that never appears for exactly the people who asked for less
   motion. Written this way, switching the animation off leaves a
   palette that is simply already there.
   ══════════════════════════════════════════════════════════════════ */

.qf{
  position:fixed;inset:0;z-index:60;
  display:grid;
  grid-template-rows:min-content;
  justify-items:center;
  /* Top-centre, just under the top edge: that is where a laptop's
     webcam is, so a dialog you read while recording keeps your eyes
     near the lens. Height follows --app-h so an iOS soft keyboard
     shrinks the overlay instead of covering its fields. */
  bottom:auto;height:var(--app-h,100dvh);
  padding:max(.75rem,env(safe-area-inset-top)) 1rem .75rem;
  background:color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter:blur(3px);
  -webkit-backdrop-filter:blur(3px);
}
.qf[hidden]{display:none}

.qf-panel{
  width:min(42rem,100%);
  max-height:min(34rem,calc(var(--app-h,100dvh) - 1.5rem));
  display:flex;flex-direction:column;
  border:1px solid var(--line);
  border-radius:calc(var(--r) + 2px);
  background:var(--panel-solid);
  box-shadow:0 24px 60px -12px rgba(0,0,0,.45), 0 0 0 1px rgba(255,255,255,.02) inset;
  overflow:hidden;
}

.qf-label{
  margin:0;padding:.5rem .9rem 0;
  font-size:.66rem;font-weight:600;text-transform:uppercase;letter-spacing:.1em;
  color:var(--ink-dim);
}

.qf-input{
  flex:none;
  margin:.25rem .6rem .5rem;
  padding:.55rem .7rem;
  border:1px solid var(--line);border-radius:9px;
  background:var(--bg);color:var(--ink);
  font:inherit;font-size:1rem;
}
.qf-input:focus{outline:2px solid var(--brand);outline-offset:1px;border-color:var(--brand)}

.qf-results{
  flex:1 1 auto;min-height:0;
  list-style:none;margin:0;padding:0 .35rem;
  overflow-y:auto;overscroll-behavior:contain;
}
.qf-row{
  display:grid;
  grid-template-columns:1fr min-content;
  grid-template-areas:"main why" "sub why";
  gap:0 .5rem;
  padding:.4rem .55rem;
  border-radius:8px;
  cursor:pointer;
}
.qf-row.on{background:var(--surf)}
.qf-row.on .qf-title{color:var(--brand)}
.qf-main{grid-area:main;display:flex;align-items:baseline;gap:.4rem;min-width:0;flex-wrap:wrap}
.qf-title{font-weight:600;font-size:.9rem;color:var(--ink)}
.qf-folder{
  font-size:.7rem;color:var(--ink-dim);
  padding:.05rem .35rem;border:1px solid var(--line);border-radius:4px;
}
.qf-tag{font-size:.7rem;color:var(--brand);opacity:.85}
.qf-sub{
  grid-area:sub;
  font-size:.76rem;color:var(--ink-dim);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.qf-why{
  grid-area:why;align-self:center;
  font-size:.64rem;text-transform:uppercase;letter-spacing:.06em;
  color:var(--ink-dim);opacity:.7;
}
.qf-empty,.qf-hint{
  flex:none;margin:0;padding:.5rem .9rem;
  font-size:.76rem;color:var(--ink-dim);
}
.qf-hint{border-top:1px solid var(--line)}

/* Decorative only — see the note above about the resting state. Both
   keyframes touch opacity and transform exclusively: animating a
   layout property here would relayout a long result list every frame. */
@keyframes qf-veil{ from{opacity:0} }
@keyframes qf-rise{ from{opacity:0;transform:translateY(-10px) scale(.985)} }

.qf.on{animation:qf-veil .16s ease both}
.qf.on .qf-panel{animation:qf-rise .2s cubic-bezier(.2,.9,.25,1) both}

/* ── activity feed ── */
.activity-actions{display:flex;gap:.5rem;padding:.5rem .9rem 0}
.activity-actions button{
  flex:1;background:var(--chip);border:1px solid var(--line-hot);border-radius:.4rem;
  color:var(--brand);font:inherit;font-weight:600;padding:.45rem .6rem;cursor:pointer;
}
.activity-actions button:hover:not(:disabled){background:var(--chip-on)}
.activity-actions button:disabled{opacity:.4;cursor:default}
.activity-list{list-style:none;margin:.6rem 0 0;padding:0 .9rem;overflow-y:auto}
.activity-row{
  display:flex;justify-content:space-between;gap:.8rem;
  padding:.45rem 0;border-bottom:1px solid var(--line);font-size:.86rem;
}
.activity-row:last-child{border-bottom:0}
.activity-when{color:var(--ink-faint);white-space:nowrap;font-size:.78rem}

/* ── focused writing view ──
   One view at a time (Write or Read) on a sheet of paper. The overlay is
   a column: a non-scrolling tool row, then the scrolling desk the sheet
   sits on — so the switch in the top-right corner can never sit on top
   of text, at any width or scroll position.
   z-index 55 sits under the dialogs (.qf, 60): quick find opened with
   Ctrl+P while in Focus must appear above the page, not behind it. */
.focus-overlay{
  position:fixed;inset:0;z-index:55;
  display:flex;flex-direction:column;
  background:color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
}
.focus-overlay[hidden]{display:none}

.focus-tools{
  flex:none;display:flex;justify-content:flex-end;align-items:center;
  gap:.4rem;padding:.55rem .75rem .45rem;
}
.focus-seg{display:inline-flex;border:1px solid var(--line);border-radius:999px;
  background:var(--panel-solid);padding:2px}
.focus-seg button{font:inherit;font-size:.78rem;font-weight:600;color:var(--ink-dim);
  background:none;border:0;border-radius:999px;padding:.3rem .7rem;cursor:pointer}
.focus-seg button[aria-pressed="true"]{background:var(--chip-on);color:var(--ink)}
.focus-tool,.focus-size select{font:inherit;font-size:.78rem;font-weight:600;color:var(--ink);
  background:var(--panel-solid);border:1px solid var(--line);border-radius:999px;
  padding:.32rem .7rem;cursor:pointer;height:2rem}
.focus-size select{padding-right:.4rem}
.focus-tool:hover,.focus-seg button:hover{color:var(--ink)}
.focus-close{
  width:2rem;height:2rem;border-radius:50%;flex:none;
  border:1px solid var(--line);background:var(--panel-solid);color:var(--ink);
  font-size:1.2rem;line-height:1;cursor:pointer;
}
.focus-close:hover,.focus-tool:hover{background:var(--surf)}
.focus-tools :focus-visible{outline:2px solid var(--brand);outline-offset:2px}

.focus-scroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  padding:.4rem 1rem 3rem}

/* ── the sheet ──
   Width is the real page width (210mm = 794px at 96dpi) and the margin
   the real print margin (20mm), so a line wraps on screen where it wraps
   on paper. Narrower than a page, the sheet fits the screen and keeps
   the page's proportions: margin and minimum height are fractions of
   the sheet's own width (container units), checked against paper.js by
   test/paper.test.js. Text stays readable-size rather than shrinking
   with the sheet, so on a phone line breaks no longer match print —
   a readable phone beats a faithful but 7px one. */
:root{
  --m-ratio-a4:0.0952381; --h-ratio-a4:1.4142857;
  --m-ratio-letter:0.0926355; --h-ratio-letter:1.2941176;
}
.focus-sheet{
  --page-w:210mm; --m-ratio:var(--m-ratio-a4); --h-ratio:var(--h-ratio-a4);
  container-type:inline-size;
  width:min(var(--page-w),100%);margin:0 auto;
}
.focus-sheet[data-page="letter"]{
  --page-w:215.9mm; --m-ratio:var(--m-ratio-letter); --h-ratio:var(--h-ratio-letter);
}

/* Paper is paper: a light sheet in both themes. The tokens are
   re-declared here so everything rendered inside (code, quotes, tables,
   tag chips) takes the light palette — not a dark-theme colour on a
   white page. */
.paper{
  --bg:#fffefb; --bg-2:#f5f1e8; --panel-solid:#fffefb;
  --line:rgba(70,58,42,.24); --line-hot:rgba(180,83,9,.42);
  --ink:#1f1a14; --ink-dim:#4f463b; --ink-faint:#6f665a;
  --brand:#a8490a; --brand-2:#6d28d9;
  --ok:#047857; --warn:#7a5a0e; --bad:#b91c1c;
  --surf:rgba(70,58,42,.06);
  --chip:rgba(180,83,9,.10); --chip-on:rgba(180,83,9,.18);
  color-scheme:light;
  color:var(--ink);
  font-family:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
  font-size:12pt;line-height:1.55;
}
.focus-page{
  display:flex;flex-direction:column;
  min-height:calc(100cqi * var(--h-ratio));
  padding:calc(100cqi * var(--m-ratio));
  background:var(--bg);
  border-radius:2px;
  box-shadow:0 1px 2px rgba(0,0,0,.18), 0 24px 60px -18px rgba(0,0,0,.45);
}

/* The editor keeps its own element; on paper it is simply the page's
   text, growing with the note (main.js sizes it) so the desk scrolls,
   not the textarea. */
.focus-page .jr-editor{
  flex:1 0 auto;width:100%;min-height:0;margin:0;padding:0;
  border:0;border-radius:0;background:transparent;box-shadow:none;
  color:var(--ink);font:inherit;line-height:inherit;
  resize:none;overflow:hidden;outline:none;
}
.focus-page #preview{flex:1 0 auto;max-width:none;padding:0;margin:0;overflow:visible}
.focus-overlay[data-view="edit"] #preview{display:none}
.focus-overlay[data-view="read"] .jr-editor{display:none}

/* ── shared view link ──
   Someone else's note on the same sheet of paper, read-only. The bar
   says so in words, above the page where it cannot be mistaken for
   part of the note. No Write switch and no Link button: there is
   nothing to edit until it is saved. */
.shared-bar{
  flex:none;display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:.4rem .5rem;margin:0 auto .45rem;padding:.35rem .5rem .35rem .8rem;
  width:min(210mm,calc(100% - 2rem));box-sizing:border-box;
  border:1px solid var(--line-hot);border-radius:999px;background:var(--chip);
}
.shared-bar[hidden]{display:none}
.shared-bar-txt{margin:0 auto 0 0;font-size:.82rem;font-weight:600;color:var(--ink)}
.shared-save{border-color:var(--line-hot);color:var(--brand)}
.focus-overlay[data-shared] .focus-seg,
.focus-overlay[data-shared] #focus-share{display:none}
.focus-overlay[data-shared="error"] #focus-print,
.focus-overlay[data-shared="error"] .focus-size{display:none}
.focus-page #shared-article{flex:1 0 auto;max-width:none;padding:0;margin:0;overflow:visible}
.shared-error h1{font-size:1.5em;margin:0 0 .6em}
.shared-error p{margin:0 0 .8em}
.shared-error-hint{color:var(--ink-dim);font-size:.92em}
.md-notelink.shared{color:inherit;text-decoration:underline dotted;text-underline-offset:2px;cursor:help}
.md-shared-media{color:var(--ink-dim)}
@media (max-width:560px){
  .shared-bar{border-radius:12px;width:calc(100% - 1rem)}
  .shared-bar-txt{flex-basis:100%;text-align:center;margin:0}
}

.share-panel{padding-bottom:.9rem}
.share-choices{display:flex;flex-direction:column;gap:.5rem;margin:.6rem .9rem 0}
.share-choice{appearance:none;font:inherit;text-align:left;cursor:pointer;
  display:flex;flex-direction:column;gap:.25rem;padding:.7rem .8rem;border-radius:.6rem;
  border:1px solid var(--line);background:var(--surf);color:var(--ink)}
.share-choice:hover{border-color:var(--line-hot)}
.share-choice:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.share-choice-title{font-weight:700;font-size:.92rem}
.share-choice-edit .share-choice-title{color:var(--brand)}
.share-choice-desc{font-size:.8rem;line-height:1.4;color:var(--ink-dim)}
.share-hub-panel #share-hub-state{margin:.6rem .9rem 0}
.share-lede{margin:.4rem .9rem .5rem;font-size:.86rem;color:var(--ink-dim);line-height:1.45}
.share-sel{display:flex;align-items:center;gap:.4rem;margin:0 .9rem .4rem;font-size:.86rem}
.share-url{margin:0 .9rem;padding:.5rem .6rem;border:1px solid var(--line);border-radius:9px;
  background:var(--bg);color:var(--ink);font:.78rem/1.35 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  resize:none;overflow-wrap:anywhere;word-break:break-all;min-height:4.2rem}
.share-url:focus{outline:2px solid var(--brand);outline-offset:1px}
.share-meta{margin:.4rem .9rem 0;font-size:.8rem;color:var(--ink-dim)}
.share-warn{margin:.4rem .9rem 0;padding:.45rem .6rem;border-radius:8px;font-size:.84rem;
  color:var(--warn);background:color-mix(in srgb, var(--warn) 12%, transparent)}
.share-warn.bad{color:var(--bad);background:color-mix(in srgb, var(--bad) 12%, transparent)}
.share-panel .qf-hint{margin:.5rem .9rem 0}
.share-actions{padding-top:.7rem}

/* ── webhooks ── */
.wh-panel{max-height:calc(var(--app-h,100dvh) - 1.5rem);overflow-y:auto;overscroll-behavior:contain;padding-bottom:.9rem}
.wh-panel > *{flex:none}
.wh-row{display:flex;gap:.6rem;align-items:flex-end;flex-wrap:wrap;margin:.2rem .9rem .4rem}
.wh-pick{flex:1 1 12rem;min-width:0}
.wh-pick select,.wh-form select{
  font:inherit;font-size:.9rem;color:var(--ink);background:var(--bg);
  border:1px solid var(--line);border-radius:.4rem;padding:.45rem .5rem;max-width:100%}
.wh-form{display:flex;flex-direction:column;gap:.6rem;margin:0 .9rem}
.wh-form > *{flex:none}
.wh-mini{border:1px solid var(--line-hot);border-radius:.4rem;background:var(--chip);color:var(--brand);
  font:inherit;font-size:.82rem;font-weight:600;padding:.4rem .7rem;cursor:pointer}
.wh-mini:hover:not(:disabled){background:var(--chip-on)}
.wh-mini:disabled{opacity:.45;cursor:default}
.wh-check{display:flex;gap:.5rem;align-items:flex-start;font-size:.86rem;line-height:1.4;color:var(--ink)}
.wh-check input{margin-top:.2rem;flex:none}
.wh-check.off{opacity:.5}
.wh-fieldset{border:1px solid var(--line);border-radius:.5rem;margin:0;padding:.4rem .7rem .7rem;display:flex;flex-direction:column;gap:.45rem;min-width:0}
.wh-fieldset legend{font-size:.72rem;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--ink-dim);padding:0 .3rem}
.wh-sub{margin:.3rem 0 0;font-size:.78rem;color:var(--ink-dim)}
.wh-count{margin:0;font-size:.84rem;color:var(--ink-dim)}
.wh-none{margin:0 .9rem;font-size:.82rem;color:var(--ink-faint)}
.wh-fieldset .wh-none{margin:0}
.wh-chips{display:flex;flex-wrap:wrap;gap:.35rem}
.wh-chip{display:inline-flex;align-items:center;gap:.35rem;padding:.25rem .55rem;border:1px solid var(--line);
  border-radius:999px;font-size:.82rem;cursor:pointer;max-width:100%;overflow-wrap:anywhere}
.wh-chip:has(input:checked){border-color:var(--brand);background:var(--chip-on)}
.wh-notes{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.3rem}
.wh-note{display:flex;justify-content:space-between;gap:.5rem;align-items:center;font-size:.86rem;overflow-wrap:anywhere}
.wh-addsel{margin:.2rem .9rem .5rem;padding:.55rem .7rem;border:1px solid var(--brand);border-radius:.5rem;
  background:color-mix(in srgb, var(--brand) 10%, transparent)}
.wh-addsel p{margin:0 0 .45rem;font-size:.86rem}
.wh-loghead{padding:.4rem 0 0}
.wh-queue{margin:0;font-size:.82rem;color:var(--ink-dim)}
.wh-queue:empty{display:none}
.wh-log{padding:0;max-height:16rem}
.wh-log-row{flex-wrap:wrap}
.wh-log-msg{flex-basis:100%;font-size:.78rem;color:var(--ink-dim);overflow-wrap:anywhere}
.wh-log-row[data-outcome="failed"] > span:first-child,
.wh-log-row[data-outcome="update-refused"] > span:first-child{color:var(--bad)}
.wh-log-row[data-outcome="delivered"] > span:first-child,
.wh-log-row[data-outcome="update-applied"] > span:first-child{color:var(--ok)}
.wh-activity{border-top:1px solid var(--line);margin-top:.6rem;padding-top:.2rem}
.wh-activity .wh-queue{margin:.2rem .9rem 0}
.wh-review-title{margin:.3rem .9rem 0;font-weight:700;font-size:1rem;overflow-wrap:anywhere}
.wh-review-status{margin:.35rem .9rem 0;font-size:.86rem;line-height:1.45}
.wh-review-status[data-tone="ok"]{color:var(--ok)}
.wh-review-status[data-tone="warn"]{color:var(--warn)}
.wh-review-status[data-tone="bad"]{color:var(--bad)}
#wh-review .wh-count{margin:.35rem .9rem 0}
#wh-review .share-warn{margin:.4rem .9rem 0}
.wh-diff{margin:.45rem .9rem 0;padding:.5rem 0;border:1px solid var(--line);border-radius:.45rem;background:var(--bg);
  font-family:var(--mono);font-size:.78rem;line-height:1.5;max-height:18rem;overflow:auto;white-space:pre}
.wh-diff:empty{display:none}
.wh-diff-line{display:block;padding:0 .6rem;min-width:max-content}
.wh-diff-line.add{background:color-mix(in srgb, var(--ok) 16%, transparent)}
.wh-diff-line.del{background:color-mix(in srgb, var(--bad) 16%, transparent);text-decoration:line-through;text-decoration-color:color-mix(in srgb, var(--bad) 60%, transparent)}
.wh-diff-more{display:block;padding:.2rem .6rem;color:var(--ink-faint)}
.wh-preview-wrap{margin:.45rem .9rem 0;font-size:.86rem}
.wh-preview-wrap summary{cursor:pointer;color:var(--ink-dim)}
.wh-preview-wrap .md{margin-top:.4rem;padding:.6rem .7rem;border:1px solid var(--line);border-radius:.45rem;max-height:16rem;overflow:auto}

/* Headings and tables in the Markdown CSS are sized in rem (the app's
   16px); on paper they follow the page's 12pt instead. */
.paper .md h1{font-size:1.7em}
.paper .md h2{font-size:1.35em}
.paper .md h3{font-size:1.12em}
.paper .md h4{font-size:1em}
.paper .md h5,.paper .md h6{font-size:.9em}
.paper .md table{font-size:.9em}

/* ── printing ──
   The print root is filled from the rendered note just before printing
   (main.js), so it always prints Read, even from Write. Named pages
   because the CSP forbids injecting a rule: the root carries
   data-page and picks the matching @page. Page numbers use @page margin
   boxes — Chrome prints them, other engines just leave them out. */
.print-root{display:none}

@page { size: A4; margin: 20mm;
  @bottom-right { content: counter(page) " / " counter(pages); font-size: 9pt; color: #6f665a; }
}
@page letter { size: letter; margin: 20mm;
  @bottom-right { content: counter(page) " / " counter(pages); font-size: 9pt; color: #6f665a; }
}

@media print{
  html,body{background:#fff !important;color:#000 !important;height:auto !important;overflow:visible !important}
  body > :not(.print-root){display:none !important}
  .print-root{display:block !important;background:#fff;page:auto}
  .print-root[data-page="letter"]{page:letter}
  .print-root.paper{--bg:#fff}
  .print-root .md{max-width:none}
  .print-root .md :is(h1,h2,h3,h4,h5,h6){break-after:avoid;page-break-after:avoid}
  .print-root .md :is(img,pre,figure,blockquote,li,.md-table-wrap,.print-media){
    break-inside:avoid;page-break-inside:avoid}
  .print-root .md pre{white-space:pre-wrap;overflow:visible;overflow-wrap:anywhere}
  .print-root .md pre code{white-space:inherit}
  .print-root .md-table-wrap{overflow:visible}
  .print-root .md table{table-layout:auto}
  .print-root .md :is(th,td){white-space:normal;overflow-wrap:anywhere}
  .print-root .md-img{max-height:230mm;width:auto;object-fit:contain;border-radius:2px}
  .print-root a{color:inherit;text-decoration:underline}
  .print-root .print-url{font-size:.85em;color:#4f463b;text-decoration:none;overflow-wrap:anywhere}
  /* A refused link prints as plain text with a quiet note — a red wavy
     strike-through means nothing on paper. */
  .print-root .md-blocked{text-decoration:none;color:inherit}
  /* A note link means nothing on paper: its shown text, plain. */
  .print-root .md-notelink{color:inherit;text-decoration:none}
  .print-root .md-notelink.ambiguous::after{content:none}
  .print-root .md-blocked-tag{font-size:.75em;font-weight:400;color:#6f665a;
    background:none;border:0;padding:0;text-transform:none;letter-spacing:0}
  .print-root .md-blocked-tag::before{content:"["}
  .print-root .md-blocked-tag::after{content:"]"}
  .print-root input[type=checkbox]{print-color-adjust:exact;-webkit-print-color-adjust:exact}
}
.print-media{display:block;margin:.6em 0;padding:.5em .8em;
  border:1px dashed var(--line);border-radius:4px;font-size:.85em;color:var(--ink-dim)}

/* ── voice/video recorder ── */
.rec-panel{padding:1rem 1.1rem 1.2rem;gap:.7rem;display:flex;flex-direction:column;
  max-height:calc(var(--app-h,100dvh) - 1.5rem);overflow-y:auto;overscroll-behavior:contain}
.rec-panel > *{flex:none}
/* Recording: only what you need while talking — the camera preview at the
   very top, under the lens, with the meter and controls directly beneath
   it so your eyes do not drift down to find Stop. Options come back when
   the take ends. */
.rec-panel.live > .rec-privacy,.rec-panel.live > .rec-mode,
.rec-panel.live > .rec-group,.rec-panel.live > .rec-dock-row{display:none}
.rec-panel.live > .rec-preview{order:-1}
.rec-panel.live.video{width:min(28rem,100%);padding-top:.55rem}
#recorder.dock-left{justify-items:start}
#recorder.dock-right{justify-items:end}
.rec-dock-row{justify-content:space-between;flex-wrap:wrap;row-gap:.35rem}
.rec-dock button{padding:.28rem .6rem;font-size:.74rem}
.rec-privacy{margin:0;font-size:.78rem;color:var(--ink-dim);line-height:1.5}
.rec-mode{align-self:flex-start}
/* Grouped controls (background music, transcription). A bordered group
   keeps the dialog readable now that it holds three clusters of options
   rather than one checkbox. */
.rec-group{
  display:flex;flex-direction:column;gap:.5rem;
  border:1px solid var(--line);border-radius:.5rem;padding:.6rem .7rem;
}
.rec-row{
  display:flex;align-items:center;gap:.5rem;
  font-size:.82rem;color:var(--ink-dim);
}
.rec-row[hidden]{display:none}
.rec-select{
  font:inherit;font-size:.85rem;color:var(--ink);background:var(--bg);
  border:1px solid var(--line);border-radius:.4rem;padding:.3rem .4rem;
  flex:1;min-width:0;
}
.rec-select:focus{outline:2px solid var(--brand);outline-offset:1px;border-color:var(--brand)}
.rec-range{flex:1;min-width:0;accent-color:var(--brand)}
.rec-vol-num{font-variant-numeric:tabular-nums;min-width:4ch;text-align:right}
.rec-check{display:flex;align-items:flex-start;gap:.5rem;font-size:.82rem;color:var(--ink-dim);cursor:pointer}
.rec-check[hidden]{display:none}
.rec-check input{margin-top:.25rem;flex:none}
.rec-check small{display:block;margin-top:.15rem;font-size:.74rem;opacity:.85;line-height:1.45}

/* Input level, so a dead mic is visible before you record two minutes
   into nothing. Width only — transform would be smoother but this is
   updated a few times a second, not per frame. */
.rec-meter{
  height:.35rem;border-radius:999px;background:var(--line);
  overflow:hidden;
}
.rec-meter[hidden]{display:none}
.rec-meter-fill{
  height:100%;width:0;border-radius:999px;background:var(--brand);
  transition:width .08s linear;
}

.rec-progress{
  margin:0;display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;
  font-size:.8rem;color:var(--ink-dim);
}
.rec-progress[hidden]{display:none}
.rec-cancel{
  border:1px solid var(--line);border-radius:.4rem;background:var(--bg);
  color:var(--ink-dim);font:inherit;font-size:.76rem;padding:.2rem .55rem;cursor:pointer;
}
.rec-cancel:hover{color:var(--ink);border-color:var(--line-hot)}
.rec-pause{background:var(--chip);color:var(--ink-dim)}
.rec-preview{width:100%;max-height:min(16rem,38vh);border-radius:.5rem;background:#000;object-fit:contain}
/* Selfie view in the preview only (see layout.js shouldMirrorPreview).
   The recorder is fed the raw stream, so the saved file is never flipped. */
.rec-preview.mirror{transform:scaleX(-1)}
.rec-preview[hidden]{display:none}
.rec-controls{display:flex;align-items:center;gap:.8rem;justify-content:center;padding-top:.3rem}
.rec-time{font-variant-numeric:tabular-nums;color:var(--ink-dim);min-width:3ch}
.rec-go{
  border:1px solid var(--line-hot);border-radius:999px;background:var(--chip);
  color:var(--brand);font:inherit;font-weight:700;padding:.55rem 1.3rem;cursor:pointer;
}
.rec-go:hover{background:var(--chip-on)}
.rec-stop{background:var(--bad);border-color:var(--bad);color:#2a0d0d}
.rec-error{margin:0;font-size:.82rem;color:var(--bad)}

/* ── Nextcloud connection ── */
.nc-panel{padding:1rem 1.1rem 1.2rem;gap:.65rem;display:flex;flex-direction:column;
  max-height:calc(var(--app-h,100dvh) - 1.5rem);overflow-y:auto;overscroll-behavior:contain}
.nc-panel > *{flex:none}
.nc-field{display:flex;flex-direction:column;gap:.3rem;font-size:.8rem;color:var(--ink-dim)}
.nc-field input{
  font:inherit;font-size:.9rem;color:var(--ink);background:var(--bg);
  border:1px solid var(--line);border-radius:.4rem;padding:.5rem .6rem;
}
.nc-field input:focus{outline:2px solid var(--brand);outline-offset:1px;border-color:var(--brand)}
.nc-controls{display:flex;gap:.6rem;flex-wrap:wrap;padding-top:.2rem}
.nc-controls button{
  border:1px solid var(--line-hot);border-radius:.4rem;background:var(--chip);
  color:var(--brand);font:inherit;font-weight:600;padding:.5rem 1rem;cursor:pointer;
}
.nc-controls button:hover{background:var(--chip-on)}
.nc-status{margin:0;font-size:.82rem;color:var(--ink-dim);min-height:1.2em}
.nc-status.bad{color:var(--bad)}
.nc-status.ok{color:var(--ok)}

@media (max-width:720px){
  .qf{padding:max(.5rem,env(safe-area-inset-top)) .5rem .5rem}
  .qf-panel,.rec-panel,.nc-panel{max-height:calc(var(--app-h,100dvh) - 1rem)}
  .jr-kbd{display:none}
}


/* ══════════════════════════════════════════════════════════════════
   Action bar, sidebar selection, bulk dialog.
   ══════════════════════════════════════════════════════════════════ */

/* ── the action bar ──
   A floating pill, but in the layout's own flow above the panes rather
   than position:absolute over them. That is the whole guarantee that it
   never covers the text being written: there is no overlap to manage,
   so the caret on the last line of a long note cannot end up under it. */
.jr-ab{
  flex:none;display:flex;align-items:center;gap:.25rem;min-width:0;
  margin:.45rem .6rem .4rem;padding:.2rem;
  background:var(--panel);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  border:1px solid var(--line);border-radius:999px;
  box-shadow:0 8px 22px -12px rgba(0,0,0,.5);
}
.jr-ab-scroll{
  flex:1;min-width:0;display:flex;align-items:center;gap:.2rem;
  overflow-x:auto;overflow-y:hidden;scrollbar-width:none;overscroll-behavior-x:contain;
}
.jr-ab-scroll::-webkit-scrollbar{display:none}
/* A soft edge where more buttons are scrolled out of view. Mask, not an
   overlay, so nothing sits on top of a button's hit area. */
.jr-ab-scroll.fade-r{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.6rem),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 1.6rem),transparent)}
.jr-ab-scroll.fade-l{-webkit-mask-image:linear-gradient(to left,#000 calc(100% - 1.6rem),transparent);
  mask-image:linear-gradient(to left,#000 calc(100% - 1.6rem),transparent)}
.jr-ab-scroll.fade-l.fade-r{
  -webkit-mask-image:linear-gradient(to right,transparent,#000 1.6rem,#000 calc(100% - 1.6rem),transparent);
  mask-image:linear-gradient(to right,transparent,#000 1.6rem,#000 calc(100% - 1.6rem),transparent)}

.jr-ab-group{flex:none;display:flex;align-items:center;gap:.05rem}
.jr-ab-group + .jr-ab-group{border-left:1px solid var(--line);padding-left:.25rem;margin-left:.1rem}

.jr-ab-btn{
  appearance:none;flex:none;display:inline-flex;align-items:center;justify-content:center;gap:.3rem;
  min-width:2rem;height:2rem;padding:0 .45rem;
  border:1px solid transparent;border-radius:999px;background:transparent;
  color:var(--ink-dim);font:inherit;font-size:.8rem;cursor:pointer;
}
.jr-ab-btn:hover:not(:disabled){background:var(--surf);color:var(--ink)}
.jr-ab-btn:active:not(:disabled){background:var(--chip-on);color:var(--brand)}
.jr-ab-btn:focus-visible{outline:2px solid var(--brand);outline-offset:-2px;color:var(--ink)}
.jr-ab-btn:disabled{opacity:.32;cursor:default}
.jr-ab{position:relative;z-index:30}   /* its menu drops over the panes */
.jr-ab-btn[aria-pressed="true"]{background:var(--chip-on);color:var(--brand)}
/* The end of the bar never scrolls away: view switch and Share. */
.jr-ab-end{flex:none;display:flex;align-items:center;gap:.3rem;
  padding-left:.35rem;margin-left:.1rem;border-left:1px solid var(--line)}
.jr-ab-end > *{flex:none}
.jr-ab-end .jr-seg button{padding:.34rem .65rem}
.jr-ab .jr-share{height:2rem;padding:0 .75rem}
/* Phones only: shows the Notes tab, from the bottom bar. */
.jr-ab-notes{display:none;appearance:none;flex:none;position:relative;align-items:center;justify-content:center;
  min-width:2.75rem;height:2.75rem;padding:0 .5rem;border:1px solid transparent;border-radius:999px;
  background:transparent;color:var(--ink);font:inherit;cursor:pointer}
.jr-ab-notes[aria-expanded="true"]{background:var(--chip-on);color:var(--brand)}
.jr-ab-notes-n{position:absolute;top:.1rem;right:.05rem;min-width:1rem;height:1rem;padding:0 .25rem;
  border-radius:999px;background:var(--brand);color:#1a1206;font-size:.62rem;font-weight:700;
  line-height:1rem;text-align:center;font-variant-numeric:tabular-nums}
.jr-ab-notes-n:empty{display:none}

/* ── preview ↔ editor ── */
/* The invisible copy of the editor that main.js measures line heights
   on. Off screen, never painted, never read out. */
.jr-mirror{position:absolute;left:-99999px;top:0;visibility:hidden;pointer-events:none;
  box-sizing:border-box;border:0;margin:0;white-space:pre-wrap;overflow-wrap:break-word;
  word-wrap:break-word;contain:layout style}
/* A short flash on the block that was clicked to jump the editor. */
#preview .md-jumped{animation:jr-jumped .9s ease-out}
@keyframes jr-jumped{from{background:color-mix(in srgb,var(--brand) 22%,transparent)}to{background:transparent}}
.jr-ab-ico{width:1rem;height:1rem;flex:none}
.jr-ab-g{display:inline-block;min-width:1ch;text-align:center;font-size:.95rem;line-height:1}
.jr-ab-h{font-weight:800}
.jr-ab-mono{font-family:var(--mono);font-size:.7rem;letter-spacing:-.04em}
.jr-ab-txt{display:none}
@media (min-width:1340px){ .jr-ab-txt{display:inline} }
@media (pointer:coarse){ .jr-ab-btn{min-width:2.6rem;height:2.6rem} }

/* One shared tooltip. Visible is the resting state (the animation only
   eases into it), so reduced motion leaves it simply present. */
.jr-tip{
  position:fixed;left:0;top:0;z-index:80;pointer-events:none;
  display:flex;align-items:center;gap:.45rem;max-width:min(24rem,calc(100vw - 16px));
  padding:.3rem .55rem;border:1px solid var(--line);border-radius:.45rem;
  background:var(--panel-solid);color:var(--ink);box-shadow:var(--shadow);
  font-size:.76rem;line-height:1.3;
  animation:jr-tip-in .12s ease both;
}
.jr-tip-kbd{
  font-family:var(--mono);font-size:.7rem;color:var(--ink-dim);white-space:nowrap;
  padding:.05rem .3rem;border:1px solid var(--line);border-radius:4px;background:var(--surf);
}
@keyframes jr-tip-in{ from{opacity:0;transform:translateY(-2px)} }

/* ── Notes tab: New + Select ── */
.jr-new{flex:none;font-weight:700;color:var(--brand);background:var(--chip);
  border-color:var(--line-hot);padding:.32rem .7rem;white-space:nowrap}
.jr-new:hover{background:var(--chip-on)}
.jr-select{flex:none;color:var(--ink-dim);padding:.32rem .6rem}
.jr-select[aria-pressed="true"]{color:var(--brand);border-color:var(--brand);background:var(--chip-on)}

.jr-selbar{flex:none;display:grid;gap:.35rem;padding:.45rem .6rem;
  border-bottom:1px solid var(--line);background:var(--chip)}
.jr-sel-count{margin:0;font-size:.78rem;font-weight:700;color:var(--brand)}
.jr-sel-acts{display:flex;flex-wrap:wrap;gap:.3rem}
.jr-sel-btn{appearance:none;font:inherit;font-size:.74rem;cursor:pointer;color:var(--ink);
  background:var(--panel-solid);border:1px solid var(--line-hot);border-radius:999px;padding:.2rem .55rem}
.jr-sel-btn:hover:not(:disabled){border-color:var(--brand);color:var(--brand)}
.jr-sel-btn:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
.jr-sel-btn:disabled{opacity:.45;cursor:default}
.jr-sel-quiet{border-color:var(--line);color:var(--ink-dim)}

.jr-item-open{-webkit-user-select:none;user-select:none}   /* Shift-click must not select text */
.jr-item-check{flex:none;align-self:center;margin:0 0 0 .45rem;width:1rem;height:1rem;cursor:pointer}
.jr-item.sel{background:var(--chip-on);border-color:var(--brand)}
@media (pointer:coarse){ .jr-item-check{width:1.3rem;height:1.3rem} }

/* ── bulk dialog ── */
.bulk-panel{width:min(30rem,100%)}
.bulk-form{display:flex;flex-direction:column;gap:.65rem}
.bulk-form .qf-label{padding:0}
.bulk-what{margin:0;font-size:.92rem;font-weight:600;color:var(--ink);overflow-wrap:anywhere}
.bulk-hint{margin:0;font-size:.76rem;line-height:1.45;color:var(--ink-dim)}
.bulk-chips{display:flex;flex-wrap:wrap;gap:.3rem;max-height:7.5rem;overflow-y:auto}
.bulk-chips:empty{display:none}

@media (max-width:540px){
  .jr-ab{margin:.35rem .45rem .3rem}
  .jr-new{padding:.3rem .6rem}
}



/* ── transcription dialog ─────────────────────────────────────────── */
/* Taller than the other nc panels and scrolls inside itself: it holds
   models, language, re-transcribe, import and dictation, and the top-
   centre dialog rule keeps it on screen at short viewport heights. */
.tx-panel{overflow-y:auto;overscroll-behavior:contain;max-height:min(46rem,calc(var(--app-h,100dvh) - 1.5rem))}
.tx-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.tx-head .qf-label{padding:0}
.tx-close{appearance:none;background:none;border:1px solid transparent;border-radius:.4rem;
  color:var(--ink-dim);font:inherit;font-size:1.3rem;line-height:1;width:2rem;height:2rem;cursor:pointer}
.tx-close:hover{color:var(--ink);border-color:var(--line)}
.tx-close:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
.tx-h{margin:.5rem 0 0;font-size:.8rem;font-weight:700;color:var(--ink)}
.tx-hint{margin:0;font-size:.76rem;color:var(--ink-dim);line-height:1.45}
.tx-models{display:flex;flex-direction:column;gap:.4rem}
.tx-model{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.2rem .6rem;
  border:1px solid var(--line);border-radius:.55rem;padding:.5rem .6rem}
.tx-model:has(input:checked){border-color:var(--line-hot);background:var(--chip)}
.tx-model-pick{display:flex;gap:.55rem;align-items:flex-start;cursor:pointer;grid-column:1 / -1;font-size:.84rem;color:var(--ink)}
.tx-model-pick input{margin-top:.2rem;flex:none;accent-color:var(--brand)}
.tx-model-pick small{display:block;color:var(--ink-dim);font-size:.74rem;line-height:1.45;margin-top:.1rem}
.tx-have{font-size:.72rem;color:var(--ok);padding-left:1.6rem}
.tx-del,.tx-small-btn,.tx-media-row button{
  border:1px solid var(--line);border-radius:.4rem;background:none;color:var(--ink-dim);
  font:inherit;font-size:.76rem;padding:.3rem .6rem;cursor:pointer;justify-self:end}
.tx-del:hover,.tx-small-btn:hover{color:var(--bad);border-color:var(--bad)}
.tx-media-row button{color:var(--brand);border-color:var(--line-hot);font-weight:600}
.tx-media-row button:hover{background:var(--chip-on)}
.tx-small-btn{align-self:flex-start}
.tx-media{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.35rem}
.tx-media-row{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"name go" "kind go";
  gap:0 .6rem;align-items:center;border:1px solid var(--line);border-radius:.5rem;padding:.4rem .55rem}
.tx-media-name{grid-area:name;font-size:.82rem;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tx-media-row small{grid-area:kind;font-size:.72rem;color:var(--ink-dim)}
.tx-media-row button{grid-area:go}
.tx-empty{font-size:.78rem;color:var(--ink-dim)}
.tx-paste{width:100%;box-sizing:border-box;resize:vertical;min-height:4.5rem;
  border:1px solid var(--line);border-radius:.5rem;background:var(--bg);color:var(--ink);
  font:inherit;font-size:.84rem;padding:.5rem .6rem}
.tx-paste:focus{outline:2px solid var(--brand);outline-offset:1px;border-color:var(--brand)}
.tx-dict{display:flex;flex-direction:column;gap:.45rem}
.tx-consent{border:1px solid var(--line-hot);border-radius:.55rem;padding:.6rem .7rem;background:var(--chip);
  font-size:.8rem;color:var(--ink);line-height:1.5}
.tx-consent p{margin:0 0 .45rem}
.rec-link{appearance:none;background:none;border:0;padding:0;color:var(--brand);font:inherit;
  text-decoration:underline;cursor:pointer}

/* ── dictation bar ────────────────────────────────────────────────── */
/* In the layout's flow, between the action bar and the panes, so it never
   covers text. Interim words are faded: they are guesses, and only final
   results are written into the note. */
.dict-bar{display:flex;align-items:center;gap:.55rem;flex-wrap:wrap;
  margin:0 .6rem .35rem;padding:.35rem .6rem;border:1px solid var(--line-hot);border-radius:.55rem;
  background:var(--chip);font-size:.8rem;color:var(--ink)}
.dict-dot{width:.55rem;height:.55rem;border-radius:50%;background:var(--bad);flex:none;
  animation:dict-pulse 1.4s ease-in-out infinite}
.dict-bar[data-state="paused"] .dict-dot{background:var(--ink-faint);animation:none}
.dict-label{font-weight:600;white-space:nowrap}
.dict-interim{flex:1 1 8rem;min-width:0;color:var(--ink-faint);font-style:italic;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dict-btn{border:1px solid var(--line);border-radius:.4rem;background:none;color:var(--ink);
  font:inherit;font-size:.76rem;padding:.2rem .6rem;cursor:pointer}
.dict-btn:hover{background:var(--chip-on)}
.dict-btn:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
.jr-ab-btn[aria-pressed="true"]{background:var(--chip-on);color:var(--bad)}
@keyframes dict-pulse{0%,100%{opacity:1}50%{opacity:.35}}
@media (prefers-reduced-motion:reduce){ .dict-dot{animation:none} }
@media (max-width:520px){
  .tx-model{grid-template-columns:1fr}
  .tx-del{justify-self:start;margin-left:1.6rem}
}

/* ══════════════════════════════════════════════════════════════════
   Note links: the [[ picker, backlinks, the link-repair prompt.
   ══════════════════════════════════════════════════════════════════ */

/* ── the picker: anchored under the caret while typing [[ ── */
.jr-linkpick{position:fixed;z-index:65;width:min(24rem,calc(100vw - 1rem));
  max-height:min(18rem,50vh);display:flex;flex-direction:column;
  border:1px solid var(--line);border-radius:var(--r);background:var(--panel-solid);
  box-shadow:0 18px 44px -12px rgba(0,0,0,.45);overflow:hidden}
.jr-linkpick[hidden]{display:none}
.jr-linkpick.on{animation:qf-rise .14s cubic-bezier(.2,.9,.25,1) both}
.jr-linkpick-head{margin:0;padding:.4rem .7rem .25rem;font-size:.66rem;font-weight:600;
  text-transform:uppercase;letter-spacing:.1em;color:var(--ink-dim)}
.jr-linkpick-list{list-style:none;margin:0;padding:0 .3rem .3rem;overflow-y:auto;
  overscroll-behavior:contain}
.jr-linkpick-row{display:flex;align-items:baseline;gap:.45rem;padding:.42rem .55rem;
  border-radius:8px;cursor:pointer;min-height:2.4rem;box-sizing:border-box;flex-wrap:wrap}
.jr-linkpick-row.on{background:var(--surf)}
.jr-linkpick-row.on .jr-linkpick-title{color:var(--brand)}
.jr-linkpick-title{font-weight:600;font-size:.88rem;color:var(--ink);min-width:0;
  overflow-wrap:anywhere}
.jr-linkpick-folder{font-size:.7rem;color:var(--ink-dim);padding:.05rem .35rem;
  border:1px solid var(--line);border-radius:4px}
.jr-linkpick-dup{font-size:.68rem;color:var(--ink-faint)}
.jr-linkpick-create .jr-linkpick-title{font-weight:500}
.jr-linkpick-create .jr-linkpick-title::before{content:"+ ";color:var(--brand)}
.jr-linkpick-empty,.jr-linkpick-hint{margin:0;padding:.4rem .7rem;font-size:.74rem;color:var(--ink-dim)}
.jr-linkpick-hint{border-top:1px solid var(--line)}
@media (max-width:560px){
  .jr-linkpick-row{min-height:2.75rem;align-items:center}
}

/* ── backlinks, under the rendered note ── */
.jr-backlinks{flex:none;width:100%;max-width:var(--measure);margin:0 auto;box-sizing:border-box;
  padding:.2rem clamp(.8rem,2.5vw,1.6rem) 6rem}
.jr-backlinks[hidden]{display:none}
#preview:has(+ .jr-backlinks:not([hidden])){padding-bottom:1.2rem}
.jr-backlinks-head{margin:0 0 .5rem;padding-top:.8rem;border-top:1px solid var(--line);
  font-size:.7rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-dim)}
.jr-backlinks-list{list-style:none;margin:0;padding:0;display:grid;gap:.35rem}
.jr-backlink{display:grid;gap:.1rem;width:100%;text-align:left;font:inherit;color:inherit;
  background:none;border:1px solid var(--line);border-radius:9px;padding:.45rem .65rem;cursor:pointer}
.jr-backlink:hover,.jr-backlink:focus-visible{border-color:var(--line-hot);background:var(--chip)}
.jr-backlink-title{font-weight:600;font-size:.86rem;color:var(--ink);display:flex;gap:.45rem;
  align-items:baseline;flex-wrap:wrap}
.jr-backlink-folder{font-size:.68rem;font-weight:400;color:var(--ink-dim)}
.jr-backlink-snip{font-size:.78rem;color:var(--ink-dim);overflow-wrap:anywhere}
.jr-backlinks-empty{margin:0;font-size:.8rem;color:var(--ink-faint)}
/* The same list, in its own dialog for Write view. */
.jr-backlinks-dlg .jr-backlinks-list{padding:.2rem .7rem .8rem;overflow-y:auto}
.jr-backlinks-dlg .jr-backlinks-empty{padding:.2rem .9rem .9rem}

/* ── "Renamed — update links?" ── */
.jr-linkfix{bottom:4.6rem;width:min(34rem,calc(100vw - 1.5rem));box-sizing:border-box;flex-wrap:wrap;row-gap:.45rem;column-gap:.5rem}
.jr-linkfix #linkfix-msg{flex:1 1 14rem;min-width:0;overflow-wrap:anywhere}
.jr-linkfix .jr-linkfix-keep{background:none;border-color:var(--line);color:var(--ink-dim)}

/* Co-editing status. A quiet pill, not a banner: it reports a fact the user
   needs on demand and should not compete with the writing. The colour only
   changes for states where something is actually different — live, or not
   connected — because a pill that changes colour on every reconnect attempt
   trains people to ignore it. */
.coedit-status{
  /* On the toolbar beside Share, so it is visible in every view and never
     covers the first line of the note. */
  display:inline-block;white-space:nowrap;
  font-size:.72rem;line-height:1;letter-spacing:.01em;
  padding:.3rem .5rem;border-radius:999px;
  border:1px solid var(--line);background:var(--surf);color:var(--ink-dim);
  pointer-events:none;user-select:none;
}
.coedit-status[data-state="live"]{border-color:var(--ok);color:var(--ok)}
.coedit-status[data-state="offline"],
.coedit-status[data-state="reconnecting"]{border-color:var(--warn);color:var(--warn)}
.coedit-status[hidden]{display:none}
@media (max-width:540px){
  /* No room on a phone bar for "Offline — not saved on this device". Show
     the short form; the full sentence stays the element's text, which is
     what a screen reader reads. */
  .coedit-status{font-size:0;padding:.3rem .4rem}
  .coedit-status::after{content:attr(data-short);font-size:.66rem}
  /* The pill already carries the state here; the dot would only repeat it in
     the width the Menu button needs. */
  .jr-ab .jr-share{padding:.3rem .55rem;font-size:.74rem}
  .jr-ab .jr-share[data-coedit] .jr-share-dot{display:none}
}
@media (max-width:430px){
  /* Narrower still, a separate pill does not fit beside Share and the Menu.
     The Share button BECOMES the status chip: dot plus the short label in
     place of the word. The pill stays in the page, visually hidden, so its
     role=status still announces the full sentence. */
  .coedit-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
  .jr-ab .jr-share[data-coedit] .jr-share-dot{display:inline-block}
  .jr-ab .jr-share[data-coedit] .jr-share-word{display:none}
  .jr-ab .jr-share[data-coedit]::after{content:attr(data-short)}
  .jr-ab .jr-share[data-coedit]{font-size:.66rem;gap:.25rem}
}
@media (max-width:400px){
  /* The word itself no longer fits: an arrow glyph, with the word kept for
     assistive tech. Unshared only — a shared note shows its state instead. */
  .jr-ab .jr-share:not([data-coedit]) .jr-share-word{position:absolute;width:1px;height:1px;
    margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .jr-ab .jr-share:not([data-coedit])::before{content:"↗";font-size:.9rem;line-height:1}
  .jr-ab .jr-share{padding:.3rem .5rem}
}
@media (max-width:389px){
  /* Small phones: the dot alone. Its colour still separates live from
     offline, the button's title says it is the share control, and the
     hidden pill still announces the full state. */
  .jr-ab .jr-share[data-coedit]::after{content:none}
}
@media (max-width:480px){ .jr-tab-notes .jr-tab-label{display:none} }
@media (max-width:340px){
  .jr-ab-end .jr-seg button{padding:0 .45rem}
}

/* ── signed-in chip ── same markup and rules in every Happy Light app.
   hl-account.js unhides it from the portal's hl_signed_in hint and fills in
   the hl_name hint as text; with no name it keeps saying "Signed in". The
   avatar is the 8×8 pixel ghost from happylight.io. Below 560px only the
   avatar shows; the link's aria-label carries the words. ── */
.hl-me{display:inline-flex;align-items:center;gap:.4rem;flex:none;max-width:13rem;
  padding:.15rem .7rem .15rem .15rem;border-radius:999px;
  border:1px solid color-mix(in srgb,var(--ok) 40%,var(--line));
  background:color-mix(in srgb,var(--ok) 9%,var(--surf,transparent));
  color:var(--ink);font-size:.78rem;font-weight:600;line-height:1.2;
  text-decoration:none;white-space:nowrap}
.hl-me:hover{border-color:color-mix(in srgb,var(--ok) 65%,transparent);
  background:color-mix(in srgb,var(--ok) 16%,var(--surf,transparent))}
.hl-me-avatar{position:relative;display:grid;place-items:center;flex:none;
  width:1.45rem;height:1.45rem;border-radius:50%;
  background:color-mix(in srgb,var(--ink) 10%,transparent)}
.hl-me-ghost{width:.8rem;height:.8rem;fill:currentColor;animation:hl-me-bob 2.4s steps(4) infinite}
.hl-me-dot{position:absolute;right:-1px;bottom:-1px;width:.5rem;height:.5rem;
  border-radius:50%;background:var(--ok);box-shadow:0 0 0 2px var(--bg)}
.hl-me-dot::after{content:"";position:absolute;inset:0;border-radius:inherit;
  background:var(--ok);animation:hl-me-ping 2.4s cubic-bezier(.22,.61,.36,1) infinite}
.hl-me-name{min-width:0;overflow:hidden;text-overflow:ellipsis}
@keyframes hl-me-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-1px)}}
@keyframes hl-me-ping{0%{transform:scale(1);opacity:.6}70%,100%{transform:scale(2.4);opacity:0}}
@media (max-width:560px){.hl-me{padding:.15rem}.hl-me-name{display:none}}
@media (prefers-reduced-motion:reduce){.hl-me-ghost,.hl-me-dot::after{animation:none}}


/* ══════════════════════════════════════════════════════════════════
   PHONES — at and below 768px (DRAWER_MAX in layout.js).
   Tabs scroll sideways across the top; the action bar moves to the
   bottom, under the thumb, in two rows (with a Notes button); every
   control is at least 44px; and the notches and home indicator get
   their safe-area insets.
   ══════════════════════════════════════════════════════════════════ */
@media (max-width:768px){
  /* The tab bar: no wordmark, the storage pill as its dot and one word,
     and 44px targets. Tabs scroll sideways; the Notes tab stays first. */
  .jr-tabbar{padding:max(.25rem,env(safe-area-inset-top)) max(.4rem,env(safe-area-inset-right)) 0 max(.4rem,env(safe-area-inset-left));gap:.25rem}
  .jr-tabbar .jr-home{display:none}
  .jr-tab{height:2.75rem;min-width:5.5rem;max-width:11rem}
  .jr-tab-notes{min-width:0}
  .jr-tab-x{width:2rem;height:2rem}
  /* Room for the title: only the showing tab carries its ×. */
  .jr-tab:not(.on) .jr-tab-x{display:none}
  .jr-tab:not(.on){padding-right:.8rem}
  .jr-tab.on{min-width:8.5rem}
  .jr-tabbar-btn{min-width:2.75rem;height:2.75rem}
  .jr-tabbar .jr-store{min-height:2.5rem;padding:.2rem .55rem}
  .jr-tabbar .jr-store-i,.jr-tabbar .jr-store-tiny{display:none}
  .jr-tabbar .jr-store{min-width:2.5rem;justify-content:center}
  .jr-side-top .jr-search{flex-basis:100%}
  .jr-viewmode{margin-left:auto}
  .jr-tabbar .hl-menu-panel{position:fixed;right:.5rem;left:auto;top:3.4rem}

  /* Touch: 44px targets in the Notes tab. */
  .jr-side .jr-btn,.jr-search{min-height:2.75rem}
  .jr-list[data-view="list"] .jr-item-open{padding:.7rem .55rem}
  .jr-item-del{opacity:1;min-width:2.75rem}
  .jr-sel-btn{min-height:2.5rem;padding:.3rem .75rem}
  .hl-me{min-height:2.5rem}
  .jr-tag{min-height:2.5rem;padding:.3rem .75rem}
  .jr-list[data-view="cards"]{grid-template-columns:minmax(0,1fr);gap:.55rem}
  .jr-list[data-view="cards"] .jr-item{min-height:0}
  .jr-viewmode-word{display:none}
  .jr-viewmode button{min-height:2.6rem;padding:0 .7rem}
  /* Many tags: one sideways-scrolling row rather than half the screen. */
  .jr-filter .jr-tags{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;padding-bottom:.1rem}
  .jr-filter .jr-tags::-webkit-scrollbar{display:none}
  .jr-filter .jr-tag{flex:none}

  /* The action bar: bottom of the screen, formatting row on top, then
     Notes · view · Share · Menu. Last in the column by order, so the
     DOM (and tab order) stay as they are. */
  .jr-ab{order:3;flex-wrap:wrap;row-gap:.15rem;border-radius:1.2rem;padding:.25rem;
    margin:.3rem max(.4rem,env(safe-area-inset-right)) max(.4rem,env(safe-area-inset-bottom)) max(.4rem,env(safe-area-inset-left))}
  .jr-ab-scroll{order:-1;flex:1 1 100%;padding-bottom:.15rem;border-bottom:1px solid var(--line)}
  .jr-ab-btn{min-width:2.75rem;height:2.75rem}
  .jr-ab-notes{display:inline-flex}
  .jr-ab-end{flex:1;border-left:0;padding-left:0;margin-left:0;gap:.25rem}
  .jr-ab-end .jr-seg{margin-right:auto}
  .jr-ab-end .jr-seg button{min-height:2.75rem;padding:0 .7rem;font-size:.78rem}
  .jr-ab .jr-share{height:2.75rem;min-width:2.75rem;justify-content:center}
  .jr-tabbar .hl-menu-item,.jr-tabbar .hl-menu-group-sum{min-height:2.75rem}

  /* Toasts clear the bottom bar. */
  .jr-toast{bottom:calc(7.4rem + env(safe-area-inset-bottom));max-width:calc(100vw - 1rem);box-sizing:border-box}
  .jr-linkfix{bottom:calc(11rem + env(safe-area-inset-bottom))}

  /* The editor gets the notch insets in landscape. */
  .jr-editor,#preview{padding-left:max(.8rem,env(safe-area-inset-left));padding-right:max(.8rem,env(safe-area-inset-right))}
}
