/* Shared UI components: buttons, cards, chips, inputs, toggles, progress, avatars. */

/* ---- Buttons ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 40px;
  padding: 0 20px;
  border-radius: var(--r-pill);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}

.btn--dark { background: var(--ink); color: #FFFFFF; }
.btn--dark:hover { background: var(--navy-2); color: #FFFFFF; }

.btn--teal { background: var(--teal); color: #FFFFFF; }
.btn--teal:hover { background: var(--teal-hover); color: #FFFFFF; }

.btn--outline { background: var(--card); border: 1px solid var(--border-2); color: var(--ink); }
.btn--outline:hover { background: var(--surface-3); color: var(--ink); }

.btn--cream { background: var(--canvas); color: var(--ink); }
.btn--cream:hover { background: #FFFFFF; color: var(--ink); }

.btn--ghost { color: var(--ink); }
.btn--ghost:hover { background: var(--surface-3); color: var(--ink); }

.btn--lg { height: 52px; padding: 0 30px; font-size: 16px; }
.btn--xl { height: 54px; padding: 0 34px; font-size: 16.5px; }
.btn--sm { height: 34px; padding: 0 15px; font-size: 13px; }

/* ---- Cards ---- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-card);
}

.card--lg { border-radius: var(--r-lg); }

/* ---- Chips / badges ---- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px;
  border-radius: var(--r-pill);
  background: var(--card);
  border: 1px solid var(--border);
  font-size: 13px;
  font-weight: 600;
  color: var(--slate);
}

.chip--tint { background: var(--teal-tint); border-color: var(--teal-border); color: var(--teal-ink); }

.tag-pill {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  font-size: 11.5px;
  font-weight: 600;
}

.tag-pill--teal { background: var(--teal-tint); color: var(--teal-ink); }
.tag-pill--coral { background: #FCEAE4; color: var(--trap); }
.tag-pill--gold { background: #F9E9C8; color: var(--warn-ink); }
.tag-pill--navy { background: var(--ink); color: #FFFFFF; }

/* ---- Form fields ---- */
.field { display: flex; flex-direction: column; gap: 6px; }

.field-label { font-size: 12.5px; font-weight: 600; color: var(--slate); }

.input, .textarea {
  border-radius: var(--r-xs);
  border: 1px solid var(--border-2);
  padding: 0 13px;
  font-size: 14px;
  background: var(--card);
  outline: none;
  width: 100%;
}

.input { height: 42px; }

.textarea { min-height: 120px; resize: vertical; padding: 11px 13px; line-height: 1.55; }

.input:focus, .textarea:focus {
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(14, 124, 123, .12);
  outline: none;
}

/* ---- Segmented control ---- */
.seg {
  display: inline-flex;
  background: var(--sand);
  border-radius: var(--r-xs);
  padding: 3px;
  gap: 2px;
}

.seg-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}

.seg-btn:hover { color: var(--ink); }

.seg-btn.is-active { background: var(--card); color: var(--ink); box-shadow: 0 1px 2px rgba(28, 27, 25, .08); }

/* ---- Toggle switch ---- */
.switch { position: relative; display: inline-flex; width: 40px; height: 23px; flex: none; cursor: pointer; }
.switch input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.switch-track {
  position: absolute; inset: 0;
  background: var(--border);
  border-radius: var(--r-pill);
  transition: background .15s ease;
}
.switch-track::after {
  content: "";
  position: absolute;
  top: 2.5px; left: 2.5px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: #FFFFFF;
  box-shadow: 0 1px 2px rgba(28, 27, 25, .18);
  transition: transform .15s ease;
}
.switch input:checked + .switch-track { background: var(--teal); }
.switch input:checked + .switch-track::after { transform: translateX(17px); }

/* ---- Progress bars ---- */
.pbar { height: 4px; background: var(--cream-line); border-radius: var(--r-pill); overflow: hidden; }
.pbar-fill { height: 100%; background: var(--teal); border-radius: var(--r-pill); }

/* ---- Avatars ---- */
.avatar {
  width: 34px; height: 34px;
  border-radius: var(--r-pill);
  overflow: hidden;
  background: var(--surface);
  border: 2px solid var(--canvas);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
}
.avatar svg { width: 100%; height: 100%; display: block; }

.avatar--initials {
  background: var(--ink);
  color: #FFFFFF;
  font-size: 10px;
  font-weight: 700;
  font-family: var(--font-serif); font-variant-numeric: tabular-nums;
}

.avatar-stack { display: flex; }
.avatar-stack > * + * { margin-left: -9px; }

/* ---- Empty state ---- */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
  padding: 48px 24px;
  color: var(--muted);
}

/* ---- ReziDay logo lockup --------------------------------------------------
   ONE definition for the whole app (components.css is loaded by base.html, so
   it reaches every page). Mark = 30px, wordmark = 19px Sora, gap = 10px. Both
   sizes are the --brand-* variables below and the mark is sized FROM them, so
   the `size` argument of partials/icons/logo.html only decides how the mark
   renders outside a lockup. Page stylesheets may only POSITION the lockup
   (padding / justify) or re-declare BOTH variables together, never resize one
   half of it — that's how it stayed inconsistent before. Exceptions, both
   deliberate: the mobile chrome scales it down (.m-header-brand /
   .com-topbar-brand) and the auth pages use a large centered hero mark
   (.brand-word--auth). */
.brand-lockup {
  --brand-mark-size: 30px;
  --brand-word-size: 19px;
  /* ⬅ THE KNOB. How far the mark sits off the computed alignment below, in px:
     POSITIVE moves the cup DOWN, negative up. 0 = the saucer on the wordmark's
     baseline. Landmarks, in case a number is easier to pick than a look:
     +3.8px = the cup's bowl on the baseline (the saucer then hangs about as far
     below it as the "y" does) · +5.1px = the mark's ink box centred on the cap
     band · +6.6px = plain vertical centring, which is where this started and
     read visibly low. It is one number for every lockup, mark size included, so
     the 26px mobile header moves by the same amount, not proportionally. */
  --brand-mark-nudge: 2px;
  display: flex; align-items: center; gap: 10px; color: var(--ink);
}
.brand-lockup:hover { color: var(--ink); }

/* The mark's alignment is Ciprian's call (2026-08-09): the SAUCER sits on the
   wordmark's baseline — the bottom of the cup and the bottom of the "R" on one
   line. `align-items: center` alone puts the mark ~6.6px lower than that at the
   30px size, because it centres against the wordmark's line box, which also
   holds the descender of the "y". Two earlier attempts read low and are worth
   knowing before "correcting" this: centring the mark's INK box on the cap band
   (0.078em) — textbook, but half the mark's height is the light ECG stroke, so
   its box sits higher than its visual mass — and the cup's bowl on the baseline
   with the saucer hanging like a descender (0.149em).

   The offset is derived, not tuned. With the mark H px tall and the wordmark F
   px, both centred in a row H tall: the saucer's bottom sits at 0.40288·H (the
   ink runs to y=48.5 in a viewBox starting at 1.55, see partials/icons/logo.html)
   and the baseline at 0.5·H + 0.28947·F (Sora 800 at line-height 1 puts its
   baseline 0.78947em below the line box's top — measured, and a pure ratio of
   the font, so it holds at any size). The difference is the translate below, and
   it needs BOTH sizes — the two lockups don't share one H/F ratio, so no single
   em value of the wordmark can align them. That's why the mark is sized from
   --brand-mark-size here rather than from the template's `size` argument: one
   number per lockup, and the offset can't drift away from it.

   To move the cup by eye, change --brand-mark-nudge above and leave the two
   factors alone — they are measurements, not taste.

   A rail that hides the wordmark has nothing left to align to and puts the
   transform back to none — shell.css / lesson.css, at their own breakpoints. */
.brand-lockup svg {
  flex: none;
  width: var(--brand-mark-size);
  height: var(--brand-mark-size);
  transform: translateY(calc(
    var(--brand-word-size) * 0.28947 - var(--brand-mark-size) * 0.40288 + var(--brand-mark-nudge)
  ));
}

.brand-word {
  font-family: var(--font-logo);
  font-size: var(--brand-word-size, 19px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--ink);
}
.brand-word span { color: var(--teal); }

/* ---- Knowledge-map preview header (partials/map_preview.html) -------------
   Shared by the dashboard map and the lessons-index "Hartă", so it lives here
   rather than in either page's stylesheet. Hidden until a cell is clicked. */
.map-sel {
  display: flex;
  align-items: center;
  gap: 16px 22px;
  flex-wrap: wrap;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 14px 18px;
  margin-bottom: 20px;
}
.map-sel[hidden] { display: none; }
.map-sel-swatch {
  width: 15px; height: 15px;
  border-radius: 5px;
  box-shadow: inset 0 0 0 1px rgba(15, 34, 48, .12);
  flex: none;
}
.map-sel-main { flex: 1; min-width: 170px; }
.map-sel-name {
  font-family: var(--font-serif);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  line-height: 1.2;
}
.map-sel-meta { margin-top: 3px; font-size: 12px; color: var(--muted-2); }

.map-sel-stats { display: flex; gap: 22px; flex: none; }
.map-sel-stats[hidden] { display: none; }
.map-sel-stat-label {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted-2);
}
.map-sel-stat-val {
  margin-top: 2px;
  /* the app's own face with tabular figures — never the mono stack */
  font-family: var(--font-serif);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
}

.map-sel-go {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--teal);
  color: #FFFFFF;
  font-size: 13px;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: 9px;
}
.map-sel-go:hover { background: var(--teal-hover); color: #FFFFFF; }
.map-sel-close {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: var(--r-pill);
  background: var(--sand);
  color: var(--muted);
}
.map-sel-close:hover { background: var(--border); color: var(--ink); }

@media (max-width: 767px) {
  /* The two stat tiles are the first thing to go when the row wraps. */
  .map-sel-stats { display: none; }
  .map-sel-go { flex: 1; justify-content: center; }
}

/* ---- Daily-target slider (from the Planner handoff) -----------------------
   Two wearers: /plan/'s "Obiective de studiu" (templates/plan.html, driven by
   planner.js) and the onboarding wizard's ritm step (onboarding/obiectiv.html,
   driven by onboarding.js). It moved out of planner.css the day the second one
   appeared — the wizard runs outside the app shell and never loads that sheet —
   exactly as the "se gândește" indicator below did for the simulator.
   ⚠️ It keeps its `pl-` prefix on purpose: partials/icons/plan_mood.html hardcodes
   `.pl-mood`, and both drivers read the same class names. Restyle here and both
   screens follow; there is no second copy to keep in step. */
.pl-target { flex: 1 1 100%; min-width: 300px; display: flex; flex-direction: column; gap: 4px; padding-top: 6px; }
.pl-target-top { display: flex; align-items: baseline; gap: 8px; }
/* The number rule travels with the component — it used to ride planner.css's figure group,
   which the wizard never loads, so the target would have printed in the body face there. */
.pl-target-val {
  font-family: var(--font-serif);
  font-variant-numeric: tabular-nums;
  font-size: 26px; line-height: 1.1; font-weight: 600; letter-spacing: -0.01em;
  color: var(--teal-ink);
}
.pl-target-unit { font-size: 12.5px; color: var(--muted-2); }

.pl-slider { position: relative; height: 50px; display: flex; align-items: center; }
.pl-slider-rail {
  position: absolute; left: 0; right: 0;
  height: 12px; border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: inset 0 1px 2px rgba(28, 27, 25, .07);
}
/* --pl-t is the 0…1 position, written by the driving script. The 23px/46px pair is the
   face's own radius/width: the fill has to stop under its centre, not at the track's end. */
.pl-slider-fill {
  position: absolute; left: 0;
  height: 12px; border-radius: var(--r-pill);
  background: var(--teal);
  border-bottom: 2px solid var(--teal-hover);
  box-sizing: border-box;
  width: calc(23px + (100% - 46px) * var(--pl-t, 0));
}
.pl-slider-face {
  position: absolute; top: 50%;
  left: calc(23px + (100% - 46px) * var(--pl-t, 0));
  transform: translate(-50%, -50%);
  width: 46px; height: 46px;
  border-radius: var(--r-pill);
  background: #FFFFFF;
  border: 1.6px solid var(--ink);
  box-shadow: 0 4px 10px rgba(15, 34, 48, .16);
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
}
.pl-mood { display: flex; }
.pl-mood[hidden] { display: none; }
.pl-slider-input {
  position: absolute; left: 0;
  width: 100%; height: 50px;
  margin: 0;
  opacity: 0;
  cursor: grab;
}
.pl-slider-ticks { display: flex; justify-content: space-between; font-size: 12px; font-weight: 500; color: var(--muted-3); }

@media (max-width: 767px) {
  /* The 300px floor is what keeps the rail readable beside its label on /plan/; on a phone
     it is the whole row and would otherwise force the card to scroll. */
  .pl-target { min-width: 0; }
}

/* ============================================================================
   PROFILE FOOT — the bottom of both sticky rails (app sidebar + lesson rail).
   Markup: partials/profile_foot.html. Lives here rather than in shell.css
   because the lesson page has its own shell and never loads that file; each
   shell supplies only its own collapsed overrides (they collapse at different
   widths — 1279px for the app sidebar, 1479px for the lesson rail).
   ========================================================================== */

/* No bottom padding of its own: the rail's own bottom inset is the whole gap
   under the row, so there is one number to reason about when placing it. */
.app-sidebar-foot { padding: 10px 0 0; border-top: 1px solid var(--divider); }

.app-prof-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px;
  border-radius: 10px;
  cursor: pointer;
  color: inherit;
}
.app-prof-row:hover { background: var(--surface); color: inherit; }
.app-prof-row.is-active { background: var(--teal-tint); }

.app-prof-link { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; color: inherit; }
.app-prof-link:hover { color: inherit; }

.app-prof-avatar { width: 34px; height: 34px; flex: none; border-radius: var(--r-pill); overflow: hidden; background: var(--surface); }
.app-prof-body { min-width: 0; flex: 1; }
/* Both line-heights are tight enough that the two-line text stack stays under
   the avatar's 34px — the avatar is what sets the row's height, so the row is
   as short as the block can be without cropping the glyph. */
.app-prof-name { font-size: 14px; line-height: 1.3; font-weight: 600; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.app-prof-sub { font-size: 11px; line-height: 1.3; color: var(--muted-2); }

.app-logout {
  flex: none;
  width: 28px; height: 28px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted-2);
}
.app-logout:hover { background: var(--surface); color: var(--slate); }

/* ── "Se gândește…": the AI's waiting indicator ────────────────────────────
   Three teal dots + a shimmering label, worn next to the Sinapsa glyph below. It is the
   app's ONE way of saying a model is working, so it is the same object wherever that
   happens: the assistant's transcript, and the simulator's two waits (one AI call per
   written subject — the per-subject "Verifică răspunsul", and the finish overlay).
   ⚠️ Here, not in lesson.css, for the same reason as the glyph: /grile/sesiune/ never
   loads lesson.css. */
.ksb-typing { display: inline-flex; align-items: center; gap: 4px; padding: 3px 0; vertical-align: middle; }
.ksb-typing i { width: 5px; height: 5px; border-radius: 50%; background: var(--teal-2); animation: ksb-dot 1.05s ease-in-out infinite; }
.ksb-typing i:nth-child(2) { animation-delay: .15s; }
.ksb-typing i:nth-child(3) { animation-delay: .3s; }
@keyframes ksb-dot { 0%, 60%, 100% { transform: translateY(0); opacity: .4; } 30% { transform: translateY(-4px); opacity: 1; } }
.ksb-typing-label {
    margin-left: 9px; font-size: 11.5px; font-weight: 600; vertical-align: middle;
    background: linear-gradient(90deg, var(--faint) 30%, var(--teal-2) 50%, var(--faint) 70%);
    background-size: 200% 100%;
    -webkit-background-clip: text; background-clip: text; color: transparent;
    animation: ksb-shimmer 1.7s linear infinite;
}
@keyframes ksb-shimmer { from { background-position: 120% 0; } to { background-position: -80% 0; } }
@media (prefers-reduced-motion: reduce) {
    .ksb-typing i, .ksb-typing-label { animation: none; }
    .ksb-typing-label { background: none; color: var(--faint); -webkit-text-fill-color: currentColor; }
}

/* ── Sinapsa: the AI mark, and its three motion states ─────────────────────
   Drawn by templates/partials/icons/ksb_sinapsa.html. Ported from the "Sinapsa variante"
   sheet, the card marked `original` — and it is the one variant on that sheet whose motion
   is pure CSS: 1a / 1d / 2a drive theirs with SMIL `<animateMotion>`, which a stylesheet
   can neither pause nor re-time. That is precisely what lets ONE drawing sit still, run at
   rest, or run quicker while the model is working, instead of needing three drawings.

   The sheet animates every copy, always. Here motion is a **STATE**: the element carries
   only its own timing (`--dur` per link, `--d` per node, the sheet's numbers), and the
   stylesheet decides whether it runs.

   ⚠️ It lives in components.css — loaded by base.html on every page — because it is worn by
   two screens that load different stylesheets: the lesson assistant (lesson.css) and the
   simulator's grading overlay (grile.css). It was in lesson.css until the second one
   needed it. Do not move it back. */
.ksb-syn-node { transform-box: fill-box; transform-origin: center; }
/* Still by default — at 15px in the mode switch, and beside a message that has already been
   answered, four flowing dashed links are noise sitting next to text. */
.ksb-syn .ksb-syn-link, .ksb-syn .ksb-syn-node { animation: none; }
/* Alive at rest (`is-live`, the chat's empty state) at the sheet's own speeds: the
   desynchronised 1.1/1.3/1.5/1.7s and the 0.55s node cascade are the sheet's, not ours —
   they are what keep it from reading as a marching band. */
.ksb-syn.is-live .ksb-syn-link,
.ksb-syn.is-thinking .ksb-syn-link,
.ksb-msg.is-typing .ksb-syn .ksb-syn-link { animation: ksb-syn-flow var(--dur, 1.4s) linear infinite; }
.ksb-syn.is-live .ksb-syn-node,
.ksb-syn.is-thinking .ksb-syn-node,
.ksb-msg.is-typing .ksb-syn .ksb-syn-node { animation: ksb-syn-node 2.2s ease-in-out var(--d, 0s) infinite; }
/* …and quicker while it thinks. That difference IS the thinking state — one glyph at two
   speeds, which is what the sheet's single always-on speed cannot express. Keep the node
   cascade proportional so the four still fire in order rather than together.
   ⚠️ `.ksb-syn.is-thinking` is the PORTABLE form and `.ksb-msg.is-typing .ksb-syn` is the
   chat's own alias for it, kept so the assistant's markup did not have to change. Anything
   outside the chat — the simulator's overlay — must use `is-thinking`: the alias only fires
   under a `.ksb-msg` ancestor, so a glyph that borrowed it elsewhere would silently sit at
   the resting speed, which is the difference between "working" and "idle". */
.ksb-syn.is-thinking .ksb-syn-link,
.ksb-msg.is-typing .ksb-syn .ksb-syn-link { animation-duration: calc(var(--dur, 1.4s) * .45); }
.ksb-syn.is-thinking .ksb-syn-node,
.ksb-msg.is-typing .ksb-syn .ksb-syn-node {
    animation-duration: 1s;
    animation-delay: calc(var(--d, 0s) * .45);
}
@keyframes ksb-syn-flow { to { stroke-dashoffset: -8; } }
@keyframes ksb-syn-node { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.3); } }
/* All of it is decoration on a waiting state — the copy already says what is happening, so
   nothing is lost by standing still.
   ⚠️ These have to REPEAT the live selectors, not shorten to `.ksb-syn-link`. A media query
   adds no specificity, so a bare class here loses to `.ksb-syn.is-live .ksb-syn-link` and the
   icon keeps animating for exactly the people who asked it not to. That shipped broken once;
   it is invisible in a screenshot and was caught by reading `animationName` back out of the
   browser under the emulated setting. */
@media (prefers-reduced-motion: reduce) {
    .ksb-syn.is-live .ksb-syn-link,
    .ksb-syn.is-live .ksb-syn-node,
    .ksb-syn.is-thinking .ksb-syn-link,
    .ksb-syn.is-thinking .ksb-syn-node,
    .ksb-msg.is-typing .ksb-syn .ksb-syn-link,
    .ksb-msg.is-typing .ksb-syn .ksb-syn-node { animation: none; }
}

/* ======================================= ACTIVITY BANDS + MARK (pl-k) ===== */

/* An activity's colour and its drawn mark — worn by the Plan calendar (planner.css:
   the week card, the agenda row, the month pill, the task dialog) AND by the home
   screen's "Planul de azi" rows (dashboard.css). It moved out of planner.css the day
   the second screen wore it, exactly as `.pl-target*` and the "se gândește" indicator
   did before it; the `pl-` prefix travels with it for the same reason — both drivers
   read these class names, and `partials/icons/plan_kind.html` is shared too.

   ⚠️ THE POINT of keeping one copy: a lesson has to be the same colour on the home
   screen and in the calendar. The colour is derived server-side from one function
   (`progress.planner.difficulty_for`) and painted through one class here, so the two
   screens cannot drift into two palettes for one fact.

   The bands, the measurements they have to keep passing, and the four constraints on
   any replacement are in tokens.css — read that before touching a hex. The default is
   `mediu`: a legible fallback, NOT a fourth band. There is no "necunoscut". */
.pl-k {
  --k-bg: var(--dif-mediu);
  --k-lip: var(--dif-mediu-lip);
  --k-ink: var(--gold-ink);
  --k-meta: rgba(58, 38, 4, .68);
  --k-glow: rgba(239, 192, 58, .30);
}
.pl-k.is-usor {
  --k-bg: var(--dif-usor);
  --k-lip: var(--dif-usor-lip);
  --k-ink: var(--dif-ink);
  --k-meta: rgba(4, 48, 47, .70);
  --k-glow: rgba(87, 196, 137, .30);
}
/* is-mediu is the default above. */
.pl-k.is-greu {
  --k-bg: var(--dif-greu);
  --k-lip: var(--dif-greu-lip);
  --k-ink: #FFFFFF;
  --k-meta: rgba(255, 255, 255, .76);
  --k-glow: rgba(110, 31, 20, .28);
}
.pl-k.is-sim {
  --k-bg: var(--navy);
  --k-lip: #08131C;
  --k-ink: #FFFFFF;
  --k-meta: rgba(255, 255, 255, .72);
  --k-glow: rgba(15, 34, 48, .28);
}

/* The mark itself. Sized by CSS, never by the SVG's own width/height, so one drawing
   serves the 13px month pill, the 18px week card, the 21px agenda row, the 22px home
   row and the 19px legend. */
.pl-kmark { flex: none; display: flex; align-items: center; justify-content: center; }
.pl-kmark svg { display: block; width: 100%; height: 100%; }
.pl-kmark[hidden] { display: none; }

/* The white disc a mark sits on. ⚠️ Load-bearing, not decoration: these are drawings at
   viewBox 48 (white paper, navy ink, teal accent), so around 18px the 2.6 stroke lands
   at ~1px and on `is-greu` it disappears entirely, leaving a white silhouette. Same
   object as `.pl-sheet-ico` in the task dialog.
   ⚠️ `display` is load-bearing too — these are <span>s, and a parent that is not a flex
   container leaves them inline, where width and height simply do not apply: the disc
   collapses and the mark lands straight on the fill. It reads as "the background did not
   apply", which is not where anyone looks. The size is the caller's. */
.pl-kdisc {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: #FFFFFF;
  box-shadow: inset 0 0 0 1px rgba(15, 34, 48, .10);
}

/* ---- The activity as a full-width ROW ----
   The Plan calendar's phone agenda (planner.js → buildRow) and the home screen's
   "Planul de azi" (templates/home.html) are the same card, so it is declared once. It
   moved out of planner.css the day the home screen wore it — same move `.pl-target*` and
   the "se gândește" indicator made, and the `pl-` prefix travels for the same reason.

   Everything it paints comes from `.pl-k` above, so a band added there reaches both
   screens. What each screen keeps for itself: the drag grip and the drop states
   (planner.css — home rows are links, not draggable), and the row's own container. */
.pl-row {
  background: var(--k-bg);
  border-bottom: 3px solid var(--k-lip);
  border-radius: 12px;
  padding: 12px 14px;
  display: flex; align-items: center; gap: 10px;
  box-shadow: 0 3px 10px var(--k-glow);
  cursor: pointer;
  transition: opacity .18s ease;
}
.pl-row.is-done { opacity: .6; }
.pl-row.is-active { box-shadow: 0 6px 16px rgba(14, 124, 123, .32); }
/* The row is full-width, not a 157px week column: it affords a bigger disc than the
   card's. ⚠️ Sized here rather than in planner.css because the home screen wears this
   row and never loads that sheet — there the disc would have had no size at all. */
.pl-row-ico { width: 32px; height: 32px; }
.pl-row-ico svg { width: 21px; height: 21px; }
.pl-row-body { flex: 1; min-width: 0; }
.pl-row-title { overflow-wrap: break-word; font-size: 13.5px; line-height: 1.35; font-weight: 600; color: var(--k-ink); }
.pl-row-meta { font-size: 11.5px; color: var(--k-meta); margin-top: 3px; }
.pl-row-meta[hidden] { display: none; }
.pl-row-check { flex: none; }
.pl-row-check[hidden] { display: none; }
/* The figure treatment travels with the component (CLAUDE.md, the number rule) — it used
   to ride planner.css's figure group, which the home screen never loads. */
.pl-row-pct {
  flex: none;
  font-family: var(--font-serif); font-variant-numeric: tabular-nums;
  font-size: 10px; font-weight: 600; color: var(--teal-ink);
  background: #FFFFFF; border-radius: var(--r-pill); padding: 2px 7px;
}
.pl-row-pct[hidden] { display: none; }
