/* --------------------------------------------------- */
/*                      READ TASK                      */
/* --------------------------------------------------- */
/* Shared between the tasks page's own .read-task-container and the
   homepage's inline read panel (scripts/taskReadPanel.js) — same markup/
   classes, same look, so a task reads identically wherever it's opened
   from. Some rules below (.relation-panel-*) only ever apply on the tasks
   page (the homepage's relation chips are non-interactive) — harmless,
   unused CSS there, kept together rather than split across two files. */
/* .read-task-parent-container is NOT part of the read-task-container
   itself — it's the tasks page's kanban "done column" layout wrapper
   (see tasks/index.html), just historically filed alongside this block. */
.read-task-parent-container {
  position: relative;
  z-index: 0;
  width: 310px;
  min-width: 310px;
  height: 95%;
  min-height: 800px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* Phone mode (issue #184's roadmap) - full-width stacked column instead of
   a fixed ~310px one squeezed alongside its 2 siblings (.main-container's
   own html.phone-mode block, tasks/styles/general.css/workspaceShell.css).
   Its own child, .task-done-container, has the matching flex:none/
   max-height/scroll override (tasks/styles/taskDone.css) - this wrapper
   just needs to stop forcing an 800px floor of its own. */
html.phone-mode .read-task-parent-container {
  /* !important - syncSidePanelWidths (tasks/scripts/init.js) is gated off
     entirely on phone now (own comment there), but this is the same
     inline-width-vs-CSS conflict as .task-column-wrapper's own identical
     note (tasks/styles/editTask.css) - kept as a safety net. */
  width: 100% !important;
  min-width: 0;
  height: auto;
  min-height: 0;
}
.read-task-container {
  position: fixed;
  width: 60vh;
  height: 60vh;
  min-width: 480px;
  min-height: 480px;
  z-index: 10;
  padding: 30px;
  background-color: var(--main-theme);
  border-top: 2px solid var(--secondary-color);
  border-bottom: 2px solid var(--secondary-color);
  border-radius: 15px;
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.6);

  opacity: 0;
  visibility: hidden;
  transform-origin: center center;
  will-change: transform, opacity;
}
/* Phone mode (issue #184's roadmap): this panel (reading a task standalone,
   or previewing it live while editing) becomes a full-screen tab instead of
   a fixed 60vh/min-480px panel glued next to the editor - sizing/position
   only here, deliberately NOT display:none. Standalone reading (tapping a
   card, no edit session open) is shown/hidden by this container's own
   inline opacity/visibility, exactly like desktop already does (set by
   readTaskFlip.js's open()/close()) - a display:none/block toggle keyed off
   .reading/.preview directly was tried first and cut the close animation
   off instantly, since every real close call site (closeReadContainer's
   callers, taskReadDetail.js) removes that class SYNCHRONOUSLY, up front,
   before the flip's own 350ms shrink-back transition even starts - the
   panel would vanish (display:none) the instant .reading was gone, well
   before the animated scale/opacity ever had a chance to render. Confirmed
   as the actual, reported bug: the open (grow-from-card) animation worked
   fine (adds .reading THEN plays it), the close (shrink-back-into-card) one
   never did. Only while actively editing (below) does a real display:none/
   block toggle still make sense - .create-section and this container both
   exist at once then, switching between the Edit/Preview tabs is instant
   with no animation to interrupt, so there's nothing for a toggle to cut
   off. */
html.phone-mode .read-task-container {
  position: fixed;
  /* !important on the individual insets (not just `inset`, which a later
     inline top/left alone can still partially beat - see below) - confirmed
     as a real bug: readTaskDrag.js's applyPos()/this panel's own open
     animation set inline top/left (its normal desktop drag-position
     system), which normally out-rank a stylesheet regardless of specificity.
     Left at 78px (an old desktop drag position) with an UNCONTESTED
     width:100vw still stretching from there overflowed the phone viewport's
     right edge by exactly that 78px - confirmed via a real Playwright
     screenshot, not just reasoned about. */
  top: 0 !important;
  left: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  width: 100% !important;
  height: 100% !important;
  min-width: 0;
  min-height: 0;
  border-radius: 0;
  overflow-y: auto;
  /* 15px, not the desktop base rule's own 30px (further up this file) -
     confirmed wanted once this became a full-screen phone panel instead of
     a fixed ~480px floating box, same "less dead space at the edges"
     reasoning as .create-section.floating-editor's own identical 15px
     phone override (editTask.css). Applies to every state this container
     can be in on phone (standalone reading, and previewing while editing) -
     the editing-specific rule just below only needs to add its own bottom
     clearance on top of this, not restate top/left/right too. */
  padding: 15px;
}
/* The drag handle repositions this panel around the screen by mouse
   (createReadContainerDragController, shared/scripts/readTaskDrag.js) -
   meaningless once the panel is a full-screen phone tab with nowhere left
   to drag it TO (its own base rule just above pins it to the whole
   viewport regardless of state), in both the reading and previewing-while-
   editing cases this file's own header comment already distinguishes.
   Hidden outright rather than just disabling drag - a visible handle that
   silently does nothing would read as broken, not as "this feature doesn't
   apply here". */
html.phone-mode .read-task-drag-handle-wrapper {
  display: none;
}
/* Standalone reading (tapping a card, no edit session open): the app's own
   top+bottom toolbars are ALSO hidden while reading now (confirmed wanted,
   matching editing's own behavior - body:has(.read-task-container.reading)
   .phone-top-toolbar/.phone-bottom-toolbar, workspaceShell.css/tasks/
   styles/general.css), so this panel needs no EXTRA clearance beyond its
   own base padding just above - the base rule's full inset:0 already gives
   it the entire screen to pad into. */
/* Editing: .create-section and this container both exist at once, so an
   instant display:none/block toggle IS correct here (no animation to
   interrupt) - .phone-tab-active decides which of the two is actually
   showing, unaffected by whatever stale .reading/.preview class this
   container happens to be separately carrying. Needs its own bottom
   clearance for the edit/preview tab bar (.phone-edit-preview-tabs) that
   standalone reading above has no equivalent of. */
html.phone-mode body:has(.create-section.floating-editor) .read-task-container {
  display: none;
  padding-bottom: 76px;
}
html.phone-mode
  body:has(.create-section.floating-editor)
  .read-task-container.phone-tab-active {
  display: block;
}
/* The origin/destination task card's own "impact" bounce once the FLIP
   open/close animation above actually reaches it (bumpCard,
   readTaskFlip.js) — same shared-keyframe idea as rs-xp-hud-bump
   (styles.css) reacting once a flying XP drop reaches the level bar it
   targeted, just scoped to the task card instead of that HUD bar. */
@keyframes task-card-flip-bump {
  0% {
    transform: scale(1);
  }
  40% {
    transform: scale(1.05) translateY(-3px);
  }
  100% {
    transform: scale(1);
  }
}
.task-card-container.task-card-flip-bump {
  animation: task-card-flip-bump 300ms ease;
}
.read-task-inner {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 10px;
}
.read-task-drag-handle-wrapper {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: var(--cursor-pointer, grab);
  height: 30px;
  width: 32px;
  border-radius: 5px;
  background-color: var(--main-theme-lighter);
  padding: 5px;
  font-size: 1.3em;
  transition: background-color 150ms;
}
.read-task-drag-handle-wrapper:hover {
  background-color: var(--main-theme-darker);
}
.read-task-drag-handle-wrapper:active {
  cursor: var(--cursor-pointer, grabbing);
}
.read-task-drag-handle {
  color: var(--secondary-color);
  font-size: 1em;
  pointer-events: none;
  transition: transform 150ms;
}
.read-task-drag-handle-wrapper:hover .read-task-drag-handle {
  transform: scale(1.25);
}
.read-task-container .line {
  width: 100%;
  border-top: 1px solid #a5a5a5;
}
.read-task-container.reading {
  /* Above the homepage's fixed corner buttons (.homepage-action,
     z-index: 40, styles.css) so the panel isn't covered while reading. Also
     above the kanban/task-overview hover float-actions button
     (#card-float-actions, z-index: 100, taskCardActions.css) — that hover
     widget's own JS already tries to never show while a reading panel is
     open (_showCardFloatActions, taskCardActions.js), but that's a
     best-effort guard against a NEW hover, not a guarantee against one
     that was already visible before this panel opened over it; the
     z-index itself is what actually guarantees the panel wins either way.
     Also above Quick Search's own .search-panel (z-index: 999, styles.css)
     and Chat's .chat-panel/.chat-users-flyout (z-index: 999) and
     .chat-emoji-picker (z-index: 1000, shared/styles/chat.css) - a task
     opened in view mode, from either the homepage's tasks side panel or the
     Tasks Workspace itself, is exactly the kind of "the user is actively
     looking at this" surface neither of those floating features should
     ever paint over, regardless of which one happened to open first. Same
     reasoning applies to .relation-panel-peek and .read-task-container.preview,
     just below - all three sit in this same "must win against Quick Search/
     Chat" tier now.

     This value alone is only HALF of that fix when this is the embedded
     Tasks Workspace's own copy (nested inside .tasks-workspace-mount, itself
     inside .body-layout - position: relative; z-index: 5, styles.css, a
     stacking context of its own) - no z-index set here, however large, ever
     escapes that boundary to compete against a real <body>-level sibling
     like Quick Search/Chat. createReadContainerFlip's own open() (shared/
     scripts/readTaskFlip.js) temporarily relocates this element to a real
     <body> child for exactly as long as it's actually open, specifically so
     this z-index value has something to actually win against - restored to
     its normal DOM position on close. A no-op for the homepage's own read
     panel (scripts/taskReadPanel.js), whose copy is already a real <body>
     child to begin with. */
  z-index: 1101;
  border: none;
}
.read-task-container.preview {
  /* Above the kanban/task-overview hover float-actions button
     (#card-float-actions, z-index: 100, taskCardActions.css) so the
     preview panel isn't covered when it overlaps a card being hovered. Also
     above .create-section.floating-editor's own z-index: 1110 (editTask.css)
     — same tier otherwise, but as siblings appended to <body> in DOM order
     (relocateCreateSectionToBody, tasks.js runs after this element already
     exists) a tie there would let the floating create/edit panel paint over
     anything that pops out of this one, like the drag handle's own tooltip
     (createTooltip, tasks/scripts/language.js) sitting right at this
     panel's edge, closest to wherever that other panel is docked. Also above
     Quick Search/Chat - see .read-task-container.reading's own comment just
     above (including why this value alone isn't the whole fix for the
     embedded copy) for why; kept 10 higher than reading/peek, same relative gap as
     before, so a tie between preview and reading never actually matters in
     practice (they're never both open at once) but stays consistent. */
  z-index: 1111;
  border-top-color: var(--grid-color);
  border-bottom-color: var(--grid-color);
}
.read-task-name-container,
.read-task-deadline-container {
  width: 100%;
  min-height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.read-text-wrapper {
  position: relative;
  width: 100%;
  flex: 1 1 0;
  min-height: 0;
}
.read-task-text-container {
  width: 100%;
  font-size: 0.8em;
  word-wrap: break-word;
  height: 100%;
  overflow-y: auto;
  /* Reserves the scrollbar's own track width permanently, whether or not
     content actually overflows right now - without this, a §-collapsible
     section expanding (shared/scripts/taskDescriptionRenderer.js) past the
     point where a scrollbar becomes needed narrows every row's available
     width the instant it appears (non-overlay scrollbars, e.g. Windows
     Chrome, physically take up horizontal space from the content box), even
     rows well above the section that expanded and have nothing to do with
     it - a checkbox label (width:86%, below) that fit on one line suddenly
     wraps to two the moment ANY scrollbar appears anywhere in this
     container. Reserving the gutter unconditionally means that width never
     changes at all, so nothing above/unrelated ever reflows just because
     something else in the same scroll container grew or shrank. */
  scrollbar-gutter: stable;
  color: var(--font-color-clear);
  background-color: rgba(0, 0, 0, 0.4);
  padding: 20px;
  border-radius: 10px;
  position: relative;
  /* This already has a definite height (100% of its own parent, not auto),
     so nothing inside it changing size ever needs to resize THIS element
     itself - but without this, the browser still doesn't know that for
     certain, and keeps recomputing layout for everything OUTSIDE this
     container too whenever something inside changes (e.g. a collapsible
     description section's own open/close height animation,
     shared/scripts/taskDescriptionRenderer.js) - `layout` only (not also
     `paint`, unlike that animated element's own containment,
     descriptionTypes.css) so this doesn't risk changing how the font-size
     slider or the image-lightbox pseudo-element (below) already interact
     with this container's existing overflow-y/position:relative. */
  contain: layout;
}
.read-font-size-slider {
  position: absolute;
  top: 6px;
  right: 16px;
  display: flex;
  align-items: center;
  gap: 4px;
  opacity: 0;
  transition: opacity 150ms;
  color: var(--font-color-weak);
  font-size: 0.75em;
  z-index: 2;
  pointer-events: none;
}
.read-text-wrapper:hover .read-font-size-slider {
  opacity: 1;
  pointer-events: auto;
}
.read-font-size-slider input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 60px;
  height: 3px;
  border-radius: 2px;
  background: var(--grid-color);
  outline: none;
  cursor: var(--cursor-pointer);
}
/* WebKit/Blink still paints a ::-webkit-slider-runnable-track pseudo-element
   over the input's own background above even with -webkit-appearance: none
   set — normally invisible (nothing else styles it), but the homepage's own
   generic input[type="range"]::-webkit-slider-runnable-track rule (its
   settings glow-radius slider, styles.css) applies site-wide and would
   otherwise paint a thicker, differently-colored track on top of this one.
   Explicit + more specific here so it wins regardless of load order. */
.read-font-size-slider input[type="range"]::-webkit-slider-runnable-track {
  height: 3px;
  border-radius: 2px;
  background: var(--grid-color);
}
.read-font-size-slider input[type="range"]::-moz-range-track {
  height: 3px;
  border-radius: 2px;
  background: var(--grid-color);
}
.read-font-size-slider input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--secondary-color);
  cursor: var(--cursor-pointer);
  /* WebKit/Blink doesn't auto-center a custom thumb over the 3px track
     above — without this it's top-aligned instead, sitting visibly low.
     -(thumb height - track height) / 2 = -(10 - 3) / 2. On the homepage
     this used to accidentally look right only because the generic
     input[type="range"]::-webkit-slider-thumb rule (styles.css, sized for
     its own 16px thumb/8px track) leaked its own -4px margin in here too —
     the tasks page never loads that stylesheet, so it had no override at
     all and sat too low. Setting it explicitly here fixes both. */
  margin-top: -3.5px;
}
.read-font-size-slider input[type="range"]::-moz-range-thumb {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: none;
  background: var(--secondary-color);
  cursor: var(--cursor-pointer);
}
.read-task-text-container.done-watermark {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext x='50' y='82' font-size='85' text-anchor='middle' fill='rgba(46%2C219%2C81%2C0.1)'%3E✔%3C%2Ftext%3E%3C%2Fsvg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 55%;
}
/* Preview's own pencil watermark fades + scales in instead of the plain
   instant swap done-watermark above gets — background-image itself can't
   be transitioned (browsers can't interpolate between two url()s, or
   between none and one), so it needs its own layer: a ::before whose
   OWN opacity/transform (both real, transitionable properties) animate
   while the image snaps onto it instantly and unnoticed underneath. Same
   image/sizing as before, just moved off .read-task-text-container itself
   and onto this pseudo. */
.read-task-text-container::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transform: scale(0.6);
  transition:
    opacity 350ms ease,
    transform 350ms ease;
}
.read-task-container.preview .read-task-text-container::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='rgba(255,255,255,0.1)' d='M362.7 19.3L314.3 67.7 444.3 197.7l48.4-48.4c25-25 25-65.5 0-90.5L453.3 19.3c-25-25-65.5-25-90.5 0zm-71 71L58.6 323.5c-10.4 10.4-18 23.3-22.2 37.4L1 481.2C-1.5 489.7.8 498.8 7 505s15.3 8.5 23.7 6.1l120.3-35.4c14.1-4.2 27-11.8 37.4-22.2L421.7 220.3 291.7 90.3z'%2F%3E%3C%2Fsvg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 38%;
  opacity: 1;
  transform: scale(1);
}
.read-task-deadline-container span {
  font-size: 0.9em;
  color: var(--font-color-clear);
  padding-left: 6px;
  font-weight: bold;
}
/* Classes, not the tasks page's own #readDeadlineDate/#readEffort ids —
   the homepage's inline read panel (scripts/taskReadPanel.js) uses its own
   ids (homeReadDeadlineDate/homeReadEffort) for the same elements, which
   an id-scoped rule would silently never match. */
.read-task-deadline-container .read-deadline-date.warn {
  color: var(--priority-two);
  background: color-mix(in srgb, var(--priority-two) 18%, transparent);
  border-radius: 4px;
  padding: 2px 6px 2px 5px;
}
.read-task-deadline-container .read-deadline-date.warn::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  margin-right: 5px;
  vertical-align: middle;
  position: relative;
  top: -1px;
}
.read-task-deadline-container .read-deadline-date.alert {
  color: var(--priority-one);
  background: color-mix(in srgb, var(--priority-one) 18%, transparent);
  border-radius: 4px;
  padding: 2px 6px 2px 5px;
}
.read-task-deadline-container .read-deadline-date.alert::before {
  content: "!";
  font-weight: 900;
  margin-right: 5px;
  font-size: 0.9em;
}
.read-task-deadline-container .read-effort {
  padding-right: 6px;
  margin-left: auto;
}
/* Colors directly off the tier itself (set via data-effort by whichever
   file populates this — tasks.js's readTask/checkTaskData, or the
   homepage's own taskReadPanel.js) rather than a separate warn/alert
   threshold — with only 3 possible values there's no "normal" state left
   needing a distinct neutral look. */
.read-task-deadline-container .read-effort[data-effort="low"] {
  color: var(--task-done);
}
.read-task-deadline-container .read-effort[data-effort="mid"] {
  color: var(--priority-two);
}
.read-task-deadline-container .read-effort[data-effort="high"] {
  color: var(--priority-one);
}
.read-task-deadline-container {
  justify-content: flex-start;
  border-radius: 10px;
}
/* Quick inline date-edit (taskCore.js's makeDeadlineQuickEditable /
   scripts/taskReadPanel.js's makeHomeDeadlineQuickEditable) - shared class
   names, so this one rule covers the mount's main view, the mount's
   relation peek, the homepage's main view, and the homepage's relation
   peek alike. */
.read-deadline-editable {
  cursor: var(--cursor-pointer, pointer);
  border-radius: 4px;
}
.read-deadline-editable:hover {
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 3px;
}
.read-deadline-quick-input-wrapper {
  position: relative;
  display: inline-flex;
  align-items: center;
  margin-left: 6px;
  width: 120px;
}
.read-deadline-quick-input {
  font-size: 0.9em;
  font-weight: bold;
  color: var(--font-color-clear);
  background: var(--card-theme);
  border: 1px solid var(--font-color-clear);
  border-radius: 4px;
  padding: 1px 24px 1px 4px;
  accent-color: var(--main-theme);
  /* Follows the homepage's own light/dark toggle (--ui-color-scheme,
     styles.css) so the native popup matches whichever theme is active
     there; falls back to dark on the standalone tasks page, which never
     defines that variable and (like #deadlineDate/#deadlineTime,
     tasks/styles/editTask.css) has no light theme of its own anyway. */
  color-scheme: var(--ui-color-scheme, dark);
  cursor: var(--cursor-pointer, pointer);
}
/* Hides the native calendar icon so the FA one below (matching
   #deadlineDate's own .picker-input-wrapper treatment, editTask.css) is
   the only one shown - same pseudo-element Chromium exposes for every
   native-picker input type, no separate time-input equivalent needed.
   Firefox has no way to hide its own native icon directly; the icon
   overlay below doubles as an opaque curtain over it, same as editTask.css. */
.read-deadline-quick-input::-webkit-calendar-picker-indicator {
  display: none;
}
.read-deadline-quick-input-icon {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--card-theme);
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
  color: var(--secondary-color);
  font-size: 0.8em;
  opacity: 0.7;
  cursor: var(--cursor-pointer, pointer);
}
.read-deadline-quick-input-icon:hover {
  opacity: 1;
}
.read-task-relations-container {
  width: 100%;
  min-height: 20px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.read-task-relations-container:empty {
  display: none;
}
.read-relations-label {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.75em;
  color: var(--font-color);
  white-space: nowrap;
  align-self: center;
  padding-right: 10px;
}
.read-task-relations-container .custom-select-chip {
  gap: 5px;
}
.read-task-relations-container .custom-select-chip-clickable {
  /* cursor now lives on the general, unscoped .custom-select-chip.
     custom-select-chip-clickable rule (shared/styles/dropdownSelect.css). */
  transition:
    background 150ms,
    border-color 150ms;
}
.read-task-relations-container .custom-select-chip-clickable:hover {
  background: color-mix(in srgb, var(--highlight) 30%, transparent);
  border-color: color-mix(in srgb, var(--highlight) 70%, transparent);
}
.relation-panel-peek {
  pointer-events: auto;
  /* Otherwise just the base .read-task-container's own z-index: 10 (above)
     — nowhere near the kanban/task-overview hover float-actions button
     (#card-float-actions, z-index: 100, taskCardActions.css), which could
     otherwise paint over an open peek panel, or Quick Search's/Chat's own
     floating panels (z-index: 999-1000, styles.css/chat.css). Same tier as
     .read-task-container.reading's own 1101 just above - both are "an open
     read view that must win against that hover widget AND Quick Search/
     Chat," and a peek never overlaps the main reading panel it sits beside,
     so their relative order against EACH OTHER doesn't matter, only against
     those other surfaces. Reaching Quick Search/Chat's own tier depends on
     openRelationPanel (tasks/scripts/taskRelations.js) appending this panel
     straight to a real <body> child rather than getTasksFloatingRoot()'s
     usual .body-layout-when-embedded target - see .read-task-container.reading's
     own comment above for why that distinction matters. */
  z-index: 1101;
}
/* Marks which of the two side-by-side panels is which while creating a
   sub-task (openSubTaskEditor, tasks/scripts/tasks.js) — the peek
   (.relation-panel-peek) keeps showing the ORIGINAL/parent task unchanged,
   while the main .read-task-container next to it holds the live
   create-form preview for the brand-new sub-task instead; both are
   otherwise identical-looking .read-task-container panels with nothing
   telling them apart. .relation-panel-subtask-origin-badge is the peek's
   own copy (openRelationPanel's subtaskOrigin option); .read-task-
   subtask-origin-badge is the main panel's (toggled directly via its own
   inline display, tasks.js — see its own default display:none, tasks/
   index.html). */
.relation-panel-subtask-origin-badge,
.read-task-subtask-origin-badge {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 6px;
  background: color-mix(in srgb, var(--highlight) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--highlight) 45%, transparent);
  color: var(--highlight);
  font-size: 0.78em;
  font-weight: bold;
}
.relation-panel-subtask-origin-badge i,
.read-task-subtask-origin-badge i {
  font-size: 0.9em;
  flex-shrink: 0;
}
.read-task-subtask-origin-badge span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.relation-panel-close-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  width: 32px;
  min-width: 32px;
  border-radius: 5px;
  background-color: var(--main-theme-lighter);
  border: none;
  color: var(--font-color-weak);
  font-size: 2em;
  line-height: 1;
  cursor: var(--cursor-pointer, pointer);
  padding: 5px;
  transition:
    background-color 150ms,
    color 150ms;
  flex-shrink: 0;
  /* Now always the sole right-side item in .read-task-category-container's
     own 3-column grid (above) - same slot the star button used to occupy
     alone before it moved into the left action group alongside edit (and
     drag, on the main read view). */
  justify-self: end;
}
.relation-panel-close-btn:hover {
  background-color: var(--main-theme-darker);
  color: var(--font-color-clear);
}
/* !important: readTask (tasks.js) sets this button's display via inline
   style whenever a task is read ("reading"), which — since a container can
   carry BOTH .reading and .preview at once (opening create/edit while
   still reading another task) — would otherwise outrank this class rule
   and leave the edit button visible on a .preview container. A preview is
   always already an editing/creating view of its own; it must never show
   a second, redundant edit button regardless of whatever inline style
   .reading left behind. */
.read-task-container.preview #readTaskEditBtn {
  display: none !important;
}
/* Same reasoning as #readTaskEditBtn just above - a .preview container is
   already an editing/creating view of its own (the real tag picker is
   right there in the create/edit form), so the quick-tag button that opens
   a SEPARATE picker on top of it would be redundant/confusing there. Only
   ever relevant to the mount's own main read view - the homepage's own
   read panel and every relation peek (mount or homepage) have no
   equivalent "editing right here" state to gate against (see this
   button's own JS wiring for why). */
.read-task-container.preview #readTaskTagsBtn {
  display: none !important;
}
/* Same reasoning as #readTaskTagsBtn just above (only ever relevant to the
   mount's own main read view) - a .preview container is already an
   editing/creating view of its own, so the quick date-edit picker
   (makeDeadlineQuickEditable, tasks/scripts/taskCore.js) that opens a
   SEPARATE input on top of it would be redundant/confusing there too.
   pointer-events: none, not display: none like the tags button - the date
   TEXT itself is legitimate live-preview content that must stay visible;
   only the click-to-edit affordance (and its hover cursor/underline,
   .read-deadline-editable below - :hover can't even match with pointer
   events off) needs to go away. This also fully disables the click
   handler itself, not just its visual affordance - a pointer-events: none
   element never becomes a click target at all. */
.read-task-container.preview #readDeadlineDate {
  pointer-events: none;
}
/* Quick inline tag-edit button (taskCreateEdit.js's initReadTagsQuickEdit-
   style wiring / scripts/taskReadPanel.js's homepage counterpart) - shared
   class name/look across all 4 read/peek contexts, same reasoning as
   .relation-panel-close-btn etc. Matches the create/edit form's own
   #taskTagsBtn (.relation-add-btn, tasks/styles/taskDependencies.css) -
   that stylesheet is tasks-page-only, so this is its own copy here in the
   shared stylesheet instead of reusing that class directly. */
.read-tags-quick-btn {
  background: none;
  border: 1px solid var(--font-color-weak);
  border-radius: 50%;
  width: 25px;
  height: 25px;
  min-width: 25px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: var(--cursor-pointer, pointer);
  color: var(--font-color-clear);
  font-size: 0.7em;
  transition:
    border-color 150ms,
    color 150ms;
}
.read-tags-quick-btn:hover {
  border-color: var(--highlight);
  color: var(--highlight);
}
.read-tags-quick-btn i {
  margin-top: 2px;
  margin-left: 1px;
}
.read-task-toolbar {
  width: 100%;
  display: flex;
  gap: 8px;
}
/* Sits alongside .read-task-subtask-btn now (fixed-width, see below)
   instead of alone — flex:1 lets it and Reopen still claim the rest of the
   row's width without hardcoding a percentage that'd have to change the
   moment that sibling's own width does. */
.read-task-complete-btn {
  flex: 1;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid color-mix(in srgb, var(--task-done) 55%, transparent);
  border-radius: 8px;
  background-color: color-mix(in srgb, var(--task-done) 14%, transparent);
  color: var(--task-done);
  font-size: 0.85em;
  font-weight: bold;
  cursor: var(--cursor-pointer, pointer);
  transition:
    background-color 150ms,
    border-color 150ms;
}
.read-task-complete-btn:hover {
  background-color: color-mix(in srgb, var(--task-done) 28%, transparent);
  border-color: var(--task-done);
}
/* Exclusive with .read-task-complete-btn above — shown only for an already-
   completed task (see readTask, tasks/scripts/tasks.js; _populateHomeReadPanel,
   scripts/taskReadPanel.js), so both never sit side by side and flex:1
   is safe for either. */
.read-task-reopen-btn {
  flex: 1;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid color-mix(in srgb, var(--secondary-color) 55%, transparent);
  border-radius: 8px;
  background-color: color-mix(in srgb, var(--secondary-color) 14%, transparent);
  color: var(--secondary-color);
  font-size: 0.85em;
  font-weight: bold;
  cursor: var(--cursor-pointer, pointer);
  transition:
    background-color 150ms,
    border-color 150ms;
}
.read-task-reopen-btn:hover {
  background-color: color-mix(in srgb, var(--secondary-color) 28%, transparent);
  border-color: var(--secondary-color);
}
/* Recolored per-task from JS (readTask, tasks/scripts/tasks.js;
   _populateHomeReadPanel, scripts/taskReadPanel.js) via --subtask-color,
   same as the rest of this panel's own per-task theming (category text,
   crown icon, container border) — falls back to --highlight if that custom
   property is ever unset. Fixed-width (not flex:1 like Complete/Reopen
   above) so it never eats into their own shared space just because its own
   label happens to be short. */
.read-task-subtask-btn {
  flex-shrink: 0;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 14px;
  border: 1px solid
    color-mix(in srgb, var(--subtask-color, var(--highlight)) 55%, transparent);
  border-radius: 8px;
  background-color: color-mix(
    in srgb,
    var(--subtask-color, var(--highlight)) 14%,
    transparent
  );
  color: var(--subtask-color, var(--highlight));
  font-size: 0.85em;
  font-weight: bold;
  cursor: var(--cursor-pointer, pointer);
  transition:
    background-color 150ms,
    border-color 150ms;
}
.read-task-subtask-btn:hover {
  background-color: color-mix(
    in srgb,
    var(--subtask-color, var(--highlight)) 28%,
    transparent
  );
  border-color: var(--subtask-color, var(--highlight));
}
/* A relation peek's own Sub-Task button, greyed out while a create/edit
   session is already open elsewhere (openRelationPanel's own
   _editOrCreateActive check, tasks/scripts/taskRelations.js) - same
   opacity/cursor treatment as this same peek's own star button gets while
   the peeked task is completed (.relation-panel-star-btn.star-btn-disabled,
   below), just under this button's own name since it's a different peek
   button. :hover falls back to the plain (non-hover) look instead of the
   normal accent tint, same reasoning as that button's own disabled :hover
   override. */
.read-task-subtask-btn.subtask-btn-disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.read-task-subtask-btn.subtask-btn-disabled:hover {
  background-color: color-mix(
    in srgb,
    var(--subtask-color, var(--highlight)) 14%,
    transparent
  );
  border-color: color-mix(
    in srgb,
    var(--subtask-color, var(--highlight)) 55%,
    transparent
  );
}
.read-task-container.preview .read-task-toolbar {
  display: none;
}
.relation-panel-edit-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  width: 32px;
  min-width: 32px;
  border-radius: 5px;
  background-color: var(--main-theme-lighter);
  border: none;
  color: var(--font-color-weak);
  font-size: 1em;
  line-height: 1;
  /* Fallback (not bare var(--cursor-pointer), unlike most of this file) —
     that custom property is only ever defined on the homepage
     (styles.css), which the tasks page (this button's actual home,
     #readTaskEditBtn) never loads, so without it this resolved to plain
     auto there instead of a pointer. Same var(--cursor-pointer, pointer)
     fallback backup.css/changelog.css already use for the same reason. */
  cursor: var(--cursor-pointer, pointer);
  padding: 5px;
  transition:
    background-color 150ms,
    color 150ms;
  flex-shrink: 0;
}
.relation-panel-edit-btn:hover {
  background-color: var(--main-theme-darker);
  color: var(--font-color-clear);
}
.relation-panel-star-btn .fa-solid.rotate {
  color: var(--highlight);
}
/* "Lit up" once favorited - same border/background-tint language the
   toolbar's own Complete/Reopen/Sub-task buttons already use below, not
   just a recolored icon, so favoriting an open task/peek reads at least as
   clearly as those do. */
.relation-panel-star-btn:has(.fa-solid.rotate) {
  border-color: color-mix(in srgb, var(--highlight) 55%, transparent);
  background-color: color-mix(in srgb, var(--highlight) 14%, transparent);
}
.relation-panel-star-btn:has(.fa-solid.rotate):hover {
  background-color: color-mix(in srgb, var(--highlight) 28%, transparent);
  border-color: var(--highlight);
}
/* Completed tasks can't be (un)starred - reading/peeking/editing one shows
   this instead of the normal hover feedback (readTaskPanel.js/
   taskReadDetail.js/taskRelations.js only ever add this class once
   isTaskDone/isTaskCompleted is already true, and skip wiring the click
   handler entirely, so this is purely visual reinforcement of that). The
   already-favorited "lit up" look (above) still shows through underneath -
   completing a task doesn't clear its favorite state, only freezes it. */
.relation-panel-star-btn.star-btn-disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.relation-panel-star-btn.star-btn-disabled:hover {
  background-color: var(--main-theme-lighter);
  color: var(--font-color-weak);
}
.relation-panel-star-btn.star-btn-disabled:has(.fa-solid.rotate):hover {
  background-color: color-mix(in srgb, var(--highlight) 14%, transparent);
  border-color: color-mix(in srgb, var(--highlight) 55%, transparent);
}
.read-task-name-container {
  min-height: 22px;
}
.read-task-name-container span {
  width: 100%;
  overflow-wrap: break-word;
  text-align: center;
  color: var(--font-color-clear);
  font-weight: bold;
}
.read-task-category-container {
  height: 30px;
  width: 100%;
  display: grid;
  /* 1fr/auto/1fr, not flex — the two side groups (drag+star+edit on the
     left, the close button alone on the right) are unequal widths; a plain
     flex row with the category pushed over via its own margin-left: auto
     only ever landed it wherever the leftover space happened to be, never a
     true center. Two equal 1fr side columns give the middle column (sized
     to the category block's own content, auto) a real horizontal center
     regardless of how many buttons sit in the left group.
     minmax(0, auto), not bare auto, for the middle track specifically - a
     grid track's own implicit minimum otherwise defaults to its content's
     min-content size (same "auto" floor a flex item gets), which for a
     long, non-wrapping category name IS its full unwrapped width -
     confirmed as the actual, reported bug: a long name (e.g.
     "WERKZEUGVERZEICHNIS") still forced this track wide enough to push the
     close button (3rd column) off the edge of a narrow phone screen despite
     the category span's own max-width/ellipsis rule further down this file
     - that rule alone was never enough, since the GRID TRACK itself was
     still refusing to shrink below the text's real width regardless of
     what the span inside it wanted to do. minmax(0, auto) explicitly lifts
     that floor to 0, letting the track (and the span's own ellipsis) size
     down to whatever's actually left over instead. */
  grid-template-columns: 1fr minmax(0, auto) 1fr;
  align-items: center;
  gap: 10px;
  /* Safety net, not the actual fix (the minmax(0, auto) column above and
     .link-text's own min-width: 0 further down are) - catches any
     leftover sub-pixel rounding overflow so a horizontal scrollbar can
     never appear here regardless. */
  overflow: hidden;
}
/* Explicit grid-column on all 3 direct children (issue #164) - without
   this, a task with no category (categoryWrapper.style.display = "none",
   taskReadDetail.js/scripts/taskReadPanel.js/taskRelations.js all toggle
   this the same way) removes the middle child from GRID AUTO-PLACEMENT
   entirely, not just from view - CSS Grid then places the remaining
   VISIBLE children into the first N tracks in DOM order, so the close
   button (3rd child) slid into track 2 (the middle, auto-sized one) instead
   of track 3, landing it dead center where the category used to be rather
   than staying pinned to the right edge. Pinning each child to its own
   named track explicitly means a hidden middle child just leaves an empty
   track behind instead of shifting anything after it over. */
.read-task-category-container > .read-task-header-actions-left {
  grid-column: 1;
}
.read-task-category-container > .read-category-clickable,
.read-task-category-container > .read-task-category-plain {
  grid-column: 2;
}
.read-task-category-container > .relation-panel-close-btn {
  grid-column: 3;
}
/* Groups whatever sits at the row's left edge (drag handle + star + edit on
   the main read view, star + edit on a relation peek) into a single grid
   item — .read-task-category-container's own grid-template-columns above
   only has 3 tracks (left/category/right), so however many buttons land on
   a given side, they need to collapse into one element to still resolve to
   exactly 3 top-level children. */
.read-task-header-actions-left {
  display: flex;
  align-items: center;
  gap: 5px;
  justify-self: start;
}
.read-category-clickable {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-self: center;
  /* min-width: 0 - this is itself the grid item sitting in the (now
     minmax(0, auto), above) middle track, and a grid item's own default
     min-width is also content-based ("auto" = min-content) same as a flex
     item's - without this, the track's own new ability to shrink still had
     nothing to actually shrink INTO, since this element (and the flex
     child inside it - see .link-text's own identical min-width: 0 further
     down) was still refusing to go below its full unwrapped content width
     right alongside it. */
  min-width: 0;
  cursor: var(--cursor-pointer);
  border-radius: 4px;
  padding: 2px 4px;
  transition: background-color 150ms;
}
.read-category-clickable:hover {
  background-color: var(--main-theme-lighter);
  cursor: var(--cursor-pointer, pointer);
}
/* Toggled by openTaskEditor (tasks/scripts/taskCreateEdit.js) for every
   create/edit session, whatever entry point it came from (a real kanban
   card's own pencil icon, the Create Task button, a sub-task, editing a
   template as a task, or the homepage's own inline side-panel path) - the
   category swatch's own "browse other tasks in this category" click
   (openCategoryMenu) has its own item-click CLOSE whatever's currently
   open to jump to reading the clicked task instead, discarding any
   unsaved edit in progress - fine while merely reading, not something a
   create/edit session should ever be one misclick away from. Same
   reasoning .read-task-category-plain (below) already uses to skip
   offering this at all on the homepage's own plain read view. Overrides
   both the base rule and its own :hover above back to a plain,
   non-interactive look - readTask (tasks/scripts/taskReadDetail.js) removes
   this class again the moment a genuine plain read of a real board task
   re-establishes a working click handler. */
.read-category-clickable.category-browse-disabled,
.read-category-clickable.category-browse-disabled:hover {
  cursor: var(--cursor-auto, auto);
  background-color: transparent;
}
.read-task-category-container #readTaskFavoriteIcon {
  font-size: 1.3em;
}
.read-task-category-container span {
  overflow-wrap: break-word;
  text-align: right;
}
/* Truncates a long category name with "..." instead of overflowing/
   squeezing the two flanking button groups (drag+edit+star on the left,
   close on the right) - same ellipsis + hover-to-slide-into-view reveal
   every other truncated title in the app already uses (.link-text,
   ellipsisReveal/ellipsisHide - shared/scripts/ellipsisReveal.js), rather
   than inventing a new pattern here. max-width (not width:100%, unlike
   that shared pattern's other uses) - this grid column's own width is
   otherwise `auto` (.read-task-category-container's own grid-template-
   columns, above), sized to fit exactly whatever this span's natural
   content width comes out to; capping the SPAN itself is what actually
   gives that auto track a real ceiling to size against; a short category
   name still renders at its own true (smaller) width either way. */
.read-category-clickable .link-text,
.read-task-category-plain .link-text {
  display: inline-block;
  max-width: 180px;
  /* This span is itself a flex child of .read-category-clickable/.read-
     task-category-plain (both display: flex) - a flex item's own default
     min-width is content-based ("auto"), which for a white-space: nowrap
     span IS its full unwrapped text width, overriding max-width/overflow/
     text-overflow entirely regardless of what they say - confirmed as the
     actual, reported reason the ellipsis never kicked in at all for a long
     category name. */
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  /* Overrides .read-task-category-container span's own text-align: right
     (above) - text-overflow: ellipsis only ever clips/dots the INLINE END
     edge (right, for ltr text); with text-align: right, the overflowing
     content sits at the START edge instead (the left), which that
     property doesn't handle at all - confirmed as the actual, reported bug
     (the text hard-clipped from its own BEGINNING with no "..." shown,
     instead of truncating from the end with one). */
  text-align: left;
}
.read-category-clickable .link-text.overflowing,
.read-task-category-plain .link-text.overflowing {
  transition: transform 2000ms linear;
}
.read-category-clickable:hover .link-text.overflowing,
.read-task-category-plain:hover .link-text.overflowing {
  text-overflow: initial;
  overflow: visible;
}
/* Homepage-only: a plain (non-clickable) stand-in for .read-category-clickable
   — the homepage's inline read panel doesn't open the tasks page's own
   "more in this category" menu, so it deliberately isn't given that
   class's pointer/hover affordance. */
.read-task-category-plain {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-self: center;
  /* Same min-width: 0 fix, same reasoning, as .read-category-clickable's
     own identical rule above - this is the grid item occupying the
     (now-shrinkable) middle track too. */
  min-width: 0;
  padding: 2px 4px;
}
.read-task-category-plain i {
  font-size: 1.3em;
}
.read-task-category-plain span {
  overflow-wrap: break-word;
  text-align: right;
}
