/* Goals — build B's Personal-goals board (tools/buildB-spec.md §5) running on
   build A's whiteboard engine.

   WHAT CAME FROM WHERE
   B supplies the content: the top banner (§5.2), the ten modules (§5.7/§5.8),
   the 1400px centred column on an 18px dotted ground, and the fact that the
   whole column — banner included — is the thing that pans and zooms.
   A supplies the machinery: one `translate() scale()` on .wb-stage, a
   board-space SVG ink layer, a pinned tool rail (add / draw / erase) and a
   pinned zoom pill. Nothing that A's engine does correctly was replaced with
   B's version of it — see the notes in js/plan.js.

   BOARD SPACE
   .board is a fixed 1400px-wide column (B's `max-width:1400px`), laid out in
   normal flow: two CSS grid rows of cards, exactly B's tracks. Cards keep their
   grid slot and are dragged by a `translate()` offset from it, so a moved card
   never reflows its neighbours — B's model, and the reason the modules can grow
   (add a goal, add a task) without colliding the way absolute placement would.

   SCREEN CHROME
   The page never scrolls on either axis. .wb-canvas is a viewport-sized window;
   everything inside .wb-stage shares one transform. The tool rail, the zoom
   pill, the picker (which also carries B's module show/hide menu) and the
   mascot sit OUTSIDE the stage and are `fixed`, so they are pinned and
   unscaled — B pins the same set.

   This file dresses plan.html, the product's one goals surface. The whiteboard
   shell, the .cal__* calendar, the tool rail and the mascot are written as
   generic pieces, but nothing else consumes them today. */

/* --- tokens ----------------------------------------------------------------
   A's base.css already matches most of B's palette exactly (--panel-alt is
   B's #FDFBF6, --border is #E5E0D7, --ink/--ink-2/--ink-4 are B's ink ramp).
   The handful of B values with no token get one here. */

.page-plan, .page-goals {
  --pl-paper: #fffdf7;
  --pl-stone: #ece7db;
  --pl-sage:  #e4eadd;
  --pl-wheat: #efe6cd;
  --pl-clay:  #e8ddd2;
  --pl-shade: #ded6c8;
  --pl-rule:  #e3ddd0;
  --pl-cast:  rgba(107, 92, 74, .18);

  /* build B, §7.3 */
  --fp-rule:      #e4ded0;   /* card border                                  */
  --fp-hair:      #efeadd;   /* hairline inside a card                       */
  --fp-ink3:      #8f8779;   /* B's third ink, a shade warmer than A's       */
  --fp-dim:       #b4ac9c;   /* micro-label                                  */
  --fp-accent:    #a2593a;   /* B's accent — A's --accent is B's doodle ink  */
  --fp-deep:      #7e3f22;   /* active/pressed text on --fp-tint             */
  --fp-tint:      #f1e3d8;
  --fp-tint-line: #dfc2ac;
  --fp-star:      #c9a24a;
  --fp-star-lit:  #e9c877;
  --fp-dot:       #d8cdb4;   /* the paper ground                             */
}

/* --- no page scrolling ----------------------------------------------------- */

body.page-plan,
body.page-goals { height: 100vh; overflow: hidden; }
body.page-plan .app,
body.page-goals .app { height: 100vh; overflow: hidden; }

.page-plan .main,
.page-goals .main { padding: 0; position: relative; height: 100vh; overflow: hidden; }

/* --- whiteboard viewport + board space -------------------------------------
   The dotted ground is painted on the viewport and panned/scaled by hand in
   js/plan.js, which is why .wb-stage can stay a zero-sized origin marker. The
   pitch and colour are B's (18px, #D8CDB4, 1.2px dots).

   Both halves of the pattern are board-space quantities: js/plan.js rewrites
   `background-size` AND the gradient's two radii with `k` folded in, so a dot
   is 1.2 BOARD px at every zoom. The declarations below are only the k = 1
   state, kept here so the ground is right before the first apply(). */

.wb-canvas {
  position: absolute;
  inset: 0;
  overflow: hidden;
  touch-action: none;
  overscroll-behavior: none;
  background-color: var(--bg);
  background-image: radial-gradient(var(--fp-dot) 1.2px, transparent 1.4px);
  background-size: 18px 18px;
  cursor: default;
}
.wb-canvas.is-grab { cursor: grab; }
.wb-canvas.is-panning { cursor: grabbing; }
.wb-canvas.is-panning .wb-stage,
.wb-canvas.is-dragging .wb-stage { user-select: none; }
.wb-canvas[data-tool="draw"] { cursor: crosshair; }
.wb-canvas[data-tool="erase"] { cursor: cell; }

/* NO `will-change: transform` here, and no 3D transform either. Either one
   promotes the stage to its own composited layer, and Chrome rasterises such a
   layer once at the scale it was promoted at and then just stretches that
   bitmap when `scale()` changes — every zoom past the promotion scale comes
   back blurred, text and CSS shapes included. Leaving the stage unpromoted
   makes the browser re-raster the vector content at each new scale, which is
   what keeps it crisp at 2.5x. The hint is added back, from the rule below,
   only while a pan is in flight — a pan changes translate only, so the raster
   scale it locks in is already the right one. */
.wb-stage {
  position: absolute;
  left: 0; top: 0;
  width: 0; height: 0;
  transform-origin: 0 0;
}
.wb-canvas.is-panning .wb-stage { will-change: transform; }

/* the freehand ink layer — board space, and never eats a pointer event */
.wb-ink {
  position: absolute;
  left: -4000px; top: -4000px;
  width: 12000px; height: 12000px;
  overflow: visible;
  pointer-events: none;
  z-index: 2;
}
.wb-stroke {
  fill: none;
  stroke: var(--accent);
  stroke-linecap: round;
  stroke-linejoin: round;
}

.wb-panels { position: absolute; left: 0; top: 0; width: 0; height: 0; z-index: 3; }

/* --- the board: B's 1400px column ------------------------------------------ */

.board {
  position: absolute;
  left: 0; top: 0;
  --board-w: 1400px;
  width: var(--board-w);
  padding: 96px 30px 130px;        /* top clears the pinned .fp-banner, 130px the toolbar */
  z-index: 1;
  font-family: var(--font-body);
}

/* --- B §5.2 top banner ------------------------------------------------------
   Board content, exactly as in B: it pans and zooms with the modules and sits
   at the top of the column, so the board "starts" with it. */

/* Anchored to the viewport, not to board space — the same treatment .wb-chrome
   gets, and pinned to the same left rail so the two line up. The board pans and
   zooms underneath it.

   pointer-events: none matters. This bar spans the full width of the canvas,
   and without it the top strip of the whiteboard would refuse to pan or draw.
   Nothing in the bar is interactive, so nothing is lost by letting clicks fall
   through to the board. */
.fp-banner {
  position: fixed;
  left: calc(var(--sidebar-w) + 21px);
  right: 21px;
  top: 18px;
  z-index: 20;
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  pointer-events: none;
}

/* The title used to sit directly on the dot grid, which is what made it hard to
   read. Its own panel — same fill, border and shadow as the chrome pills — lifts
   it off the background. */
.fp-banner__id {
  display: flex; align-items: baseline; gap: 12px;
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 9px 18px;
  box-shadow: 0 4px 14px rgba(27, 25, 22, .08);
}
.fp-banner__title {
  font-family: var(--font-hand); font-weight: 600;
  font-size: 30px; line-height: 1.05; color: var(--ink);
}
.fp-banner__date { font-size: 13px; color: var(--fp-ink3); }
.fp-banner__stat {
  margin-left: auto;
  display: flex; align-items: center; gap: 14px;
  background: var(--panel-alt);
  border: 1px solid var(--fp-rule);
  border-radius: 20px;
  padding: 8px 16px;
  box-shadow: 0 4px 14px rgba(27, 25, 22, .08);
  font-size: 12.5px; color: var(--ink-2);
  white-space: nowrap;
}
.fp-banner__stars { color: var(--fp-star); }
.fp-banner__letter { color: var(--ink-4); }

/* Narrow viewports: let the stat pill drop under the title rather than collide
   with it, and pull the board's top padding in to match. */
@media (max-width: 1000px) {
  .fp-banner { gap: 10px; }
  .fp-banner__stat { margin-left: 0; }
  .fp-banner__title { font-size: 25px; }
}

/* --- B §5.7 the two grid rows ---------------------------------------------- */

.fp-row { display: grid; gap: 18px; align-items: start; }
.fp-row--1 { grid-template-columns: 1.15fr 1fr 0.85fr; margin-bottom: 18px; }
.fp-row--2 { grid-template-columns: repeat(3, 1fr); }
.fp-col { display: flex; flex-direction: column; gap: 18px; min-width: 0; }

/* --- card chrome ------------------------------------------------------------
   `--dx/--dy` is the drag offset from the grid slot (js/plan.js writes it).
   Keeping the card in flow is what lets a growing card push its column-mate
   down instead of landing on top of it. */

.fp-card {
  position: relative;
  transform: translate(var(--dx, 0px), var(--dy, 0px));
  touch-action: none;
  min-width: 0;
  background: var(--panel-alt);
  border: 1px solid var(--fp-rule);
  border-radius: 14px;
  padding: 18px 20px;
  color: var(--ink-2);
}
.fp-card.is-dragging { z-index: 12; cursor: grabbing; }
.fp-card[hidden] { display: none; }

.fp-card--goals   { padding: 20px 22px; }
.fp-card--habits  { background: var(--fp-habits-bg); border-color: var(--fp-habits-line); }
.fp-card--wins    { background: var(--fp-wins-bg); border-color: var(--fp-wins-line); }
.fp-card--letter  { border-color: var(--border-soft); }

.fp-card__x {
  position: absolute; top: 10px; right: 12px;
  color: var(--ink-4); font-size: 12px; line-height: 1;
  z-index: 6; padding: 2px 4px; border-radius: 4px;
}
.fp-card__x:hover { color: var(--accent); background: var(--sunken); }

/* shared micro-label + hand title + "+ add" button + inline add input */
.fp-label {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .13em;
  color: var(--fp-ink3); text-transform: uppercase;
}
.fp-title {
  font-family: var(--font-hand); font-weight: 600; font-size: 19px;
  color: var(--ink-2);
}
.fp-add {
  display: block; text-align: left; margin-top: 12px;
  font-size: 12.5px; font-weight: 500; color: var(--fp-accent);
}
.fp-foot { font-size: 10.5px; color: var(--fp-faint); margin-top: 10px; }
.fp-input {
  width: 100%; margin-top: 8px;
  background: #fff; border: 1px solid var(--border);
  border-radius: 8px; padding: 7px 10px;
  font-family: var(--font-body); font-size: 12.5px; color: var(--ink);
}
.fp-input[hidden] { display: none; }

/* --- 1. semester goals ------------------------------------------------------ */

.fp-goals__head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.fp-goals__hint { font-size: 11px; color: var(--ink-4); }
.fp-goals__list { display: flex; flex-direction: column; gap: 16px; margin-top: 16px; }

.fp-goal { position: relative; display: flex; align-items: flex-start; gap: 9px; }
.fp-goal__badge {
  flex: 0 0 22px; width: 22px; height: 22px; margin-top: 6px;
  border-radius: 50%; display: grid; place-items: center;
  font-family: var(--font-body); font-size: 11px; font-weight: 600; color: #fff;
  background: var(--badge);
}
.fp-goal.is-done .fp-goal__badge { background: var(--green); }
.fp-goal__card {
  flex: 1 1 auto; min-width: 0;
  background: #fff; border: 1px solid var(--border);
  border-radius: 10px; padding: 10px 12px;
}
.fp-goal__row { display: flex; align-items: center; gap: 10px; }
.fp-goal__name {
  flex: 1 1 auto; min-width: 0; text-align: left;
  font-family: var(--font-hand); font-size: 16px; color: var(--ink);
}
.fp-goal.is-done .fp-goal__name { color: var(--ink-3); text-decoration: line-through; }
.fp-goal__rank {
  flex: 0 0 20px; width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--fp-tint); border: 1px solid var(--fp-tint-line);
  font-family: var(--font-mono); font-size: 10px; color: var(--fp-deep);
}
.fp-goal__rename {
  flex: 1 1 auto; min-width: 0;
  border: 1px solid var(--fp-tint-line); border-radius: 6px; padding: 3px 7px;
  font-family: var(--font-hand); font-size: 16px; color: var(--ink); background: #fff;
}
.fp-goal__sum {
  font-size: 12px; color: var(--fp-ink3);
  margin-top: 8px; padding-top: 7px; border-top: 1px solid var(--fp-hair);
}
.fp-goal__edit {
  margin: 8px 0 0 27px; padding-left: 14px;
  border-left: 2px solid var(--fp-tint-line);
}
.fp-goal__edit[hidden] { display: none; }
.fp-goal__field { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.fp-goal__field:first-child { margin-top: 0; }
.fp-goal__field span { flex: 0 0 40px; font-size: 12px; color: var(--fp-accent); }
.fp-goal__field input {
  flex: 1 1 auto; min-width: 0;
  border: 1px solid var(--border); border-radius: 6px; padding: 4px 8px;
  font-size: 12px; color: var(--ink); background: #fff;
}
.fp-goals__add { margin-top: 16px; font-size: 13px; }
.fp-goals__note { font-size: 10.5px; color: var(--fp-dim); margin-top: 14px; }

.fp-check {
  appearance: none;
  flex: 0 0 15px; width: 15px; height: 15px;
  border: 1.4px solid var(--ink-3); border-radius: 3px;
  background: transparent; cursor: pointer;
}
.fp-check:checked { background: var(--green); border-color: var(--green); }

/* --- 2. calendar ------------------------------------------------------------ */

.fp-cal__head { display: flex; align-items: center; justify-content: center; gap: 14px; }
.fp-cal__nav {
  flex: 0 0 26px; width: 26px; height: 26px; border-radius: 50%;
  background: var(--bg); border: 1px solid var(--border);
  color: var(--accent); font-size: 13px; line-height: 1;
  display: grid; place-items: center;
}
.fp-cal__nav:hover { background: var(--fp-tint); }
.fp-cal__title {
  font-family: var(--font-hand); font-weight: 600; font-size: 20px;
  color: var(--fp-ink3); text-align: center; min-width: 150px;
}
.fp-cal__dow, .fp-cal__grid {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px;
}
.fp-cal__dow { margin-top: 12px; }
.fp-cal__dow span {
  font-family: var(--font-mono); font-size: 8px; color: var(--fp-dim); text-align: center;
}
.fp-cal__grid { margin-top: 4px; }
.fp-cal__day {
  height: 22px; border-radius: 6px;
  display: grid; place-items: center;
  font-size: 10px; color: var(--ink-2); background: var(--sunken);
}
.fp-cal__day.is-out { background: transparent; color: var(--fp-dim); }
.fp-cal__day.is-today {
  background: #fff; border: 1px solid var(--fp-accent);
  color: var(--fp-accent); font-weight: 600;
}

/* --- 3. habits + star jar --------------------------------------------------- */

.fp-habits__title { color: var(--fp-gold-ink); }
.fp-habit { margin-top: 14px; }
.fp-habit__name { font-size: 13px; color: var(--ink-2); }
.fp-habit__dots { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.fp-habit__dot {
  width: 9px; height: 9px; flex: 0 0 9px; padding: 0;
  border-radius: 50%; cursor: pointer;
  border: 1px solid var(--fp-rule); background: transparent;
  transform: none;
  transition: background .15s, border-color .15s, transform .15s;
}
.fp-habit__dot.is-on {
  transform: scale(1.15);
  border: 1px solid var(--fp-star);
  background: var(--fp-star-lit);
}
.fp-habits__cap { font-size: 11px; color: var(--fp-gold); margin-top: 16px; }

.fp-jar { position: relative; width: 210px; height: 280px; margin: 8px auto 0; }
/* Only the two jar plates are full-bleed. This used to read `.fp-jar img`,
   which also matched every star — and at (0,1,1) it outweighed the (0,1,0)
   `.fp-jar__star` below, so each star was laid out 210x280 instead of 37x36
   and spilled far outside the jar. Naming the two plates keeps the star rule
   in charge of the stars. */
.fp-jar__back,
.fp-jar__front { position: absolute; left: 0; top: 0; width: 210px; height: 280px; }
.fp-jar__back  { z-index: 1; }
.fp-jar__front { z-index: 3; }
/* z-index 2 = between the two plates, so the jar's front glass and lip wash
   over the pile. B animates the newest star with `animation:fpdrop`, a keyframe
   that is never defined anywhere in its bundle, so that star renders opacity:0
   and stays invisible. Ported without the animation — every star is drawn. */
.fp-jar__star {
  position: absolute;
  width: 37px; height: 36px;      /* star.png at its native 37x36 */
  z-index: 2;
  transform-origin: 50% 50%;      /* JAR_PILE is solved for a centre rotation */
}
.fp-jar__label { font-size: 11px; color: var(--fp-gold); margin-top: 6px; text-align: center; }

/* --- 4. this week ----------------------------------------------------------- */

.fp-week__head { display: flex; align-items: center; justify-content: center; gap: 12px; }
.fp-week__nav {
  flex: 0 0 24px; width: 24px; height: 24px; border-radius: 50%;
  background: var(--bg); border: 1px solid var(--border);
  color: var(--accent); font-size: 12px; line-height: 1;
  display: grid; place-items: center;
}
.fp-week__nav:hover { background: var(--fp-tint); }
.fp-week__title {
  font-family: var(--font-hand); font-size: 19px; color: var(--fp-ink3);
  text-align: center; min-width: 0; flex: 1 1 auto;
}
.fp-week__grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin-top: 12px; }
.fp-week__day {
  font-family: var(--font-mono); font-size: 8.5px; color: var(--ink-4);
  text-align: center; margin-bottom: 5px;
}
.fp-week__chip {
  font-family: var(--font-mono); font-size: 8.5px;
  padding: 3px 5px; border-radius: 4px; text-align: center;
  color: var(--ink); margin-top: 4px;
}

/* --- 5. to do list ---------------------------------------------------------- */

.fp-todo__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.fp-todo__title {
  font-family: var(--font-hand); font-weight: 600; font-size: 22px;
  letter-spacing: .05em; color: var(--ink-warm);
}
.fp-todo__date { font-family: var(--font-mono); font-size: 9px; color: var(--fp-ink3); }
.fp-todo__rule { height: 1px; background: var(--border-soft); margin: 10px 0 12px; }
.fp-todo__row { display: flex; align-items: center; gap: 10px; margin-top: 9px; font-size: 13px; color: var(--ink-2); }
.fp-todo__row:first-child { margin-top: 0; }
.fp-todo__row.is-done span { color: var(--ink-4); text-decoration: line-through; }

/* --- 6. letter to future self ----------------------------------------------- */

.fp-letter__none { display: block; width: 100%; text-align: center; }
.fp-letter__none img { width: 300px; max-width: 100%; height: auto; margin: 10px auto 0; }
.fp-letter__cap { font-size: 12px; color: var(--fp-ink3); margin-top: 10px; text-align: center; }
.fp-letter__text {
  width: 100%; margin-top: 10px;
  background: var(--fp-cream); border: 1px solid var(--border);
  border-radius: 8px; padding: 10px 12px;
  font-size: 13px; min-height: 110px; resize: vertical;
  font-family: var(--font-hand); color: var(--ink);
}
.fp-letter__when {
  font-family: var(--font-mono); font-size: 8px; letter-spacing: .1em;
  color: var(--fp-ink3); margin-top: 12px;
}
.fp-letter__date {
  width: 100%; margin-top: 5px;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  padding: 7px 10px; font-size: 12.5px; color: var(--ink);
}
/* The seal button no longer stands alone — it shares a row with `cancel`, so
   the gap above it belongs to the row, not to the button. */
.fp-letter__actions { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
.fp-letter__seal {
  background: var(--accent); color: var(--panel-alt);
  border-radius: 8px; padding: 7px 14px; font-size: 12px; font-weight: 600;
}
/* Quiet next to the seal: leaving the editor is the escape hatch, not the
   thing the card is asking you to do. */
.fp-letter__cancel { font-size: 12px; color: var(--ink-4); }
.fp-letter__cancel:hover { color: var(--accent); }
/* Centred under the caption so it reads as part of the delivered letter rather
   than a control competing with the envelope. */
.fp-letter__edit {
  display: block; margin: 8px auto 0;
  font-size: 12px; color: var(--ink-4);
}
.fp-letter__edit:hover { color: var(--accent); text-decoration: underline; }
/* No error colour exists in the palette — this is --accent walked toward
   brick, so it reads as a complaint without leaving the warm ground. Visibility
   is the `hidden` property alone, which base.css enforces with !important. */
.fp-letter__err {
  --fp-err: #9c3b2c;
  font-size: 12px; margin-top: 8px; line-height: 1.4; color: var(--fp-err);
}
.fp-letter__stack {
  position: relative; width: 340px; max-width: 100%; height: 352px;
  margin: 8px auto 0; perspective: 1200px; cursor: pointer;
}
.fp-letter__stack img { position: absolute; left: 50%; width: 340px; height: auto; }
.fp-letter__open {
  top: 0; margin-left: -170px;
  transform-origin: 50% 20%;
  transition: transform .55s cubic-bezier(.5, -.2, .3, 1.2), opacity .4s ease;
}
.fp-letter__closed {
  top: 78px; margin-left: -170px;
  transform-origin: 50% 80%;
  transition: transform .55s cubic-bezier(.5, -.2, .3, 1.2), opacity .4s ease;
}
.fp-letter__stack .fp-letter__open   { transform: rotateX(70deg) scale(.95); opacity: 0; }
.fp-letter__stack .fp-letter__closed { transform: rotateX(0deg) scale(1); opacity: 1; }
.fp-letter__stack.is-open .fp-letter__open   { transform: rotateX(0deg) scale(1); opacity: 1; }
.fp-letter__stack.is-open .fp-letter__closed { transform: rotateX(70deg) scale(.95); opacity: 0; }
.fp-letter__body {
  position: absolute; left: 14%; top: 9%; width: 72%; max-height: 170px;
  overflow: hidden; z-index: 4;
  font-family: var(--font-hand); font-size: 13.5px; line-height: 1.45;
  color: var(--ink-warm); white-space: pre-wrap; opacity: 0;
  transition: opacity .4s ease;
}
.fp-letter__stack.is-open .fp-letter__body { opacity: 1; }

/* --- 7. long-term goals ------------------------------------------------------ */

.fp-long__sub { font-size: 11.5px; color: var(--ink-4); margin: 6px 0 14px; text-wrap: pretty; }
.fp-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.fp-chip {
  font-size: 12.5px; background: var(--panel-alt);
  border: 1px solid var(--fp-rule); border-radius: 8px;
  padding: 7px 12px; color: var(--ink-2); white-space: nowrap;
  display: inline-flex; align-items: center; gap: 8px;
}
.fp-chip__x { font-size: 11px; color: var(--ink-4); line-height: 1; }
.fp-chip__x:hover { color: var(--accent); }

/* --- 8. people I met --------------------------------------------------------- */

.fp-person { margin-top: 12px; }
.fp-person:first-child { margin-top: 10px; }
.fp-person__name { font-size: 13.5px; color: var(--ink); }
.fp-person__note { font-size: 12px; color: var(--fp-accent); }
.fp-person__note small { color: var(--ink-4); margin-left: 6px; }

/* --- 9. wins log -------------------------------------------------------------- */

.fp-wins__head { display: flex; align-items: center; gap: 6px; }
.fp-wins__star { color: var(--fp-star); font-size: 12px; }
.fp-wins__label { font-family: var(--font-mono); font-size: 9px; letter-spacing: .13em; color: var(--fp-gold); }
.fp-win { font-size: 13.5px; color: var(--ink-2); margin-top: 9px; }

/* --- 10. skill in progress ----------------------------------------------------- */

.fp-skill__label { font-family: var(--font-mono); font-size: 9px; letter-spacing: .13em; color: var(--fp-ink3); }
.fp-skill__row { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.fp-skill__name {
  flex: 0 0 64px; width: 64px; font-size: 13px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fp-skill__bar {
  flex: 1 1 auto; height: 7px; border-radius: 4px;
  background: var(--border-soft); overflow: hidden; cursor: pointer; padding: 0;
}
.fp-skill__fill { display: block; height: 100%; background: var(--fp-accent); }
.fp-skill__wks { flex: 0 0 auto; font-family: var(--font-mono); font-size: 8.5px; color: var(--fp-dim); }
.fp-skill__x { flex: 0 0 auto; font-size: 11px; color: var(--ink-4); line-height: 1; }
.fp-skill__x:hover { color: var(--accent); }

/* --- B §5.9 cursor-following tip ---------------------------------------------- */

.fp-tip {
  position: fixed; z-index: 400; left: 0; top: 0;
  background: var(--accent); color: var(--panel-alt);
  font-size: 11.5px; line-height: 1.5;
  padding: 8px 12px; border-radius: 10px; max-width: 250px;
  pointer-events: none; font-family: var(--font-body);
  box-shadow: 0 6px 18px rgba(27, 25, 22, .18);
  opacity: 0; transition: opacity .25s ease;
}
.fp-tip.is-on { opacity: 1; }

/* --- generic .cal__* calendar (Figma 388:571) ---------------------------------- */

.cal__month { font-family: var(--font-hand); font-size: 17px; line-height: 25px; color: var(--ink-2); }
.cal__grid {
  display: grid;
  grid-template-columns: repeat(7, 39.8px);
  column-gap: 10.2px; row-gap: 10px;
  margin-top: 5px;
}
.cal__dow {
  font-family: var(--font-body); font-size: 8px; font-weight: 500;
  color: var(--ink-3); text-align: center; height: 11px;
}
.cal__day {
  height: 23px; border-radius: 10px; background: var(--pl-shade);
  display: grid; place-items: center;
  font-family: var(--font-body); font-size: 8px; color: var(--ink-2);
}
.cal__day--mute { background: var(--ink-3); color: var(--panel-alt); }
.cal__day--dark { background: var(--fp-cal-dark); }
.cal__day--today { background: #fff; border: 1px solid var(--accent); color: var(--accent); font-weight: 600; }

/* --- added panels (A's + tool) ------------------------------------------------- */

.wb-note {
  position: absolute;
  width: 236px;
  background: var(--pl-paper);
  border: 1px solid var(--pl-rule);
  border-radius: 10px;
  box-shadow: 2px 4px 10px var(--pl-cast);
  transform: rotate(var(--rot, -.6deg));
  padding: 10px 14px 14px;
  font-family: var(--font-body);
  color: var(--ink-2);
}
.wb-note--checklist { background: var(--panel-alt); }
.wb-note--habit     { background: var(--panel-alt); }
.wb-note--people    { background: var(--pl-sage); border-color: var(--fp-sage-line); }
.wb-note--wins      { background: var(--pl-stone); }

.wb-note__label {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-family: var(--font-hand); font-size: 14px; color: var(--ink-3);
  cursor: grab;
}
.wb-note__del { font-size: 15px; line-height: 1; color: var(--ink-4); }
.wb-note__del:hover { color: var(--accent); }
.wb-note__body { margin-top: 8px; font-size: 12px; color: var(--ink); line-height: 1.5; }
.wb-note__body [contenteditable] { outline: none; }
.wb-note__body [contenteditable]:empty::before { content: attr(data-placeholder); color: var(--ink-4); }
.wb-note__text { min-height: 72px; }
.wb-note__row { display: flex; align-items: center; gap: 9px; margin-top: 8px; }
.wb-note__row input[type="checkbox"] {
  appearance: none; width: 13px; height: 13px; flex: 0 0 13px;
  border: 1.3px solid var(--ink-3); border-radius: 3px; background: transparent; cursor: pointer;
}
.wb-note__row input[type="checkbox"]:checked { background: var(--pl-sage); border-color: var(--green); }
.wb-note__row > [contenteditable] { flex: 1 1 auto; }
.wb-note__add {
  display: block; text-align: left; margin-top: 10px;
  font-size: 11px; font-weight: 500; color: var(--accent);
}
.wb-note__foot { font-size: 10px; color: var(--ink-3); margin-top: 10px; }
.wb-note__dots { display: flex; gap: 6.9px; margin-top: 10px; }

/* the habit template's dots, also used by the Brain Dump board */
.habit__dot {
  width: 9.1px; height: 9.1px; flex: 0 0 9.1px; border-radius: 50%;
  border: 1px solid var(--star); background: transparent;
  cursor: pointer;
}
.habit__dot.is-on { background: var(--star); }

/* --- screen chrome: tools, zoom, mascot ---------------------------------------- */

.wb-chrome {
  position: fixed;
  left: calc(var(--sidebar-w) + 21px);
  bottom: 22px;
  z-index: 20;
  display: flex; align-items: center; gap: 12px;
}
.wb-chrome > * {
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: 0 4px 14px rgba(27, 25, 22, .08);
  padding: 6px;
  display: flex; flex-direction: row; align-items: center; gap: 4px;
}

.pl-tools button, .gb-tools button { width: 38px; height: 38px; display: grid; place-items: center; border-radius: 999px; }
.pl-tools button:hover, .gb-tools button:hover { background: var(--pl-clay); }
.pl-tools img, .gb-tools img { width: 28px; height: 28px; }
.pl-tools button.is-on, .gb-tools button.is-on { background: var(--fp-tint); box-shadow: inset 0 0 0 1.5px var(--fp-deep); }

.wb-zoom__step {
  width: 30px; height: 30px; border-radius: 999px;
  font-size: 17px; line-height: 1; color: var(--ink-2);
}
.wb-zoom__step:hover { background: var(--pl-clay); }
.wb-zoom__level {
  min-width: 42px; border-radius: 999px; padding: 4px 6px;
  font-family: var(--font-mono); font-size: 9px; color: var(--fp-ink3);
}
.wb-zoom__level:hover { background: var(--pl-clay); color: var(--accent); }

/* erase-all sits in the same pill family as the tools and the zoom stepper;
   .wb-chrome > * already supplies its pill, and the global [hidden] rule is
   what shows and hides the wrapper. */
.wb-clear__btn {
  padding: 6px 12px; border-radius: 999px;
  font-size: 12px; color: var(--ink-2);
}
.wb-clear__btn:hover { background: var(--pl-clay); }
/* armed = one more tap wipes every stroke, so it stops looking like a label */
.wb-clear__btn.is-armed {
  background: var(--fp-tint);
  color: var(--accent); font-weight: 600;
}

/* --- the + tool's popover: A's panel templates, then B's module menu ------------ */

.wb-picker {
  position: fixed;
  left: calc(var(--sidebar-w) + 21px);
  bottom: 84px;
  z-index: 25;
  width: 244px;
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(27, 25, 22, .12);
  padding: 12px 14px 10px;
}
.wb-picker[hidden] { display: none; }
.wb-picker__title {
  font-family: var(--font-mono); font-size: 8.5px; letter-spacing: .13em;
  color: var(--fp-ink3); margin-bottom: 9px; text-transform: uppercase;
}
.wb-picker__grid { display: flex; flex-direction: column; gap: 2px; }
.wb-picker__opt {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 7px 8px; border-radius: 8px;
  font-family: var(--font-body); font-size: 13px; color: var(--ink-2);
  text-align: left;
}
.wb-picker__opt:hover { background: var(--sunken); color: var(--ink); }
.wb-picker__swatch {
  flex: 0 0 26px; width: 26px; height: 22px; border-radius: 4px;
  border: 1px solid var(--pl-rule); background: var(--pl-paper);
  position: relative; overflow: hidden;
}
.wb-picker__swatch::after {
  content: ''; position: absolute; left: 4px; right: 4px; top: 5px; height: 2px;
  background: var(--placeholder);
  box-shadow: 0 5px 0 var(--placeholder), 0 10px 0 var(--placeholder);
}
.wb-picker__swatch--checklist { background: var(--panel); }
.wb-picker__swatch--habit { background: var(--panel); }
.wb-picker__swatch--habit::after { box-shadow: 0 6px 0 var(--star); background: var(--star); opacity: .5; }
.wb-picker__swatch--people { background: var(--pl-sage); }
.wb-picker__swatch--wins { background: var(--pl-stone); }

.wb-picker__rule { height: 1px; background: var(--fp-hair); margin: 12px 0 11px; }
.wb-picker__mod {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 5px 8px; border-radius: 8px;
  font-size: 13px; color: var(--ink-warm); text-align: left;
}
.wb-picker__mod:hover { background: var(--sunken); }
.wb-picker__dot {
  flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%;
  background: var(--green);
}
.wb-picker__mod.is-off .wb-picker__dot { background: var(--fp-off); }
.wb-picker__mod.is-off { color: var(--ink-4); }

/* The pigeon is chrome, not board content: it is the companion that is always
   there, so it must not be pannable off-screen or blown up by the zoom. */
.pl-mascot, .gb-mascot {
  position: fixed;
  right: 28px; bottom: 92px;
  /* Goals gets its own, smaller bird: here it stands on a planet, so the stack
     is roughly twice as tall as the bird alone and --mascot-sm read as too big.
     ~72% of --mascot-sm, still scaling with the screen the same way. */
  --goals-pigeon: clamp(110px, min(19.7vh, 12.2vw), 245px);
  width: calc(var(--goals-pigeon) * 1.127);   /* pigeon, planet and overlap all scale off --goals-pigeon */
  pointer-events: none;
  z-index: 15;
}
.pl-mascot .pigeon, .gb-mascot .pigeon { width: var(--goals-pigeon); }
.pl-mascot .planet, .gb-mascot .planet { width: calc(var(--goals-pigeon) * .959); margin: calc(var(--goals-pigeon) * -.13) 0 0 calc(var(--goals-pigeon) * -.041); }

/* ===========================================================================
   PHONES + SMALL TABLETS (≤ 900px)
   A pannable 1400px whiteboard does not work under a thumb, so the board is
   laid out as a normal scrolling page: banner, then every card in one column,
   then any notes added with +. js/plan.js stops panning and wheel-zooming at
   this width; card positions saved on a desktop are ignored here, not lost.
   Doodles are board-space drawings, so they are hidden rather than misplaced,
   and the draw/erase/zoom controls go with them.
   =========================================================================== */
@media (max-width: 900px) {
  body.page-plan, body.page-goals,
  body.page-plan .app, body.page-goals .app { height: auto; overflow: visible; }
  body.page-plan, body.page-goals { overflow-x: hidden; }
  .page-plan .main, .page-goals .main { height: auto; overflow: visible; padding: 72px 16px 110px; display: flex; flex-direction: column; }

  .wb-canvas {
    position: static;
    overflow: visible;
    touch-action: auto;
    background-color: transparent;
    background-image: none !important;
  }
  .wb-stage { position: static; width: auto; height: auto; transform: none !important; }
  .wb-ink, .wb-clear, .wb-zoom,
  .pl-tools [data-tool="draw"], .pl-tools [data-tool="erase"] { display: none !important; }

  .board { position: static; width: auto; padding: 0; }
  .fp-row--1, .fp-row--2 { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .fp-row--1 { margin-bottom: 14px; }
  .fp-col { gap: 14px; }
  .fp-card { transform: none; touch-action: auto; padding: 16px; }

  .wb-panels { position: static; width: auto; height: auto; display: grid; gap: 14px; margin-top: 14px; }
  .wb-note { position: relative; left: auto !important; top: auto !important; width: auto !important; transform: none; }

  .fp-banner {
    position: static;
    order: -1;
    margin-bottom: 14px;
    pointer-events: auto;
    gap: 8px;
  }
  .fp-banner__id { flex-wrap: wrap; padding: 8px 14px; gap: 2px 10px; }
  .fp-banner__title { font-size: 24px; }
  .fp-banner__stat { margin-left: 0; font-size: 12px; }

  .wb-chrome { left: 16px; bottom: 16px; }
  .wb-picker { left: 16px; right: 16px; width: auto; bottom: 76px; max-height: 60vh; }

  .pl-mascot, .gb-mascot { right: 6px; bottom: 12px; --goals-pigeon: clamp(64px, 18vw, 96px); }
}
