/* ============================================================================
   patch-v2.css — hierarchy, stage identity, re-cut ramp
   ----------------------------------------------------------------------------
   Layered ON TOP of styles.css. Load it last:

       <link rel="stylesheet" href="css/styles.css">
       <link rel="stylesheet" href="css/shell.css">
       <link rel="stylesheet" href="css/patch-v2.css">

   Nothing here needs a markup change. Three things are marked NEEDS-JS and are
   noted at the foot of the file — they are the only parts CSS cannot reach.

   It changes four things, in this order of consequence:

     1. The ramp. Pink stops meaning "rank 1" so it can go back to meaning
        "act on this". Rank 3 and rank 4 stop being the same hex.
     2. Stage identity. A stage gets a CODE (S1..S5) and a slate tone, carried
        on the axis cell and the column head. Mastery colour is left alone —
        it stays on the bar fill and the pips, and nowhere else.
     3. Hierarchy. One raised surface per page instead of eight equal cards.
     4. States. Free / with somebody / back for review stop being one row
        treatment with a chip on it.
   ========================================================================== */

/* --------------------------------------------------------- 1. the brand ramp */
/* NOT re-cut. styles.css's own hexes stand — pink, yellow, green, turquoise —
   and scoring.js's RAMP matches them. The muted version read as mature and lost
   the thing these bars are for: telling the four states apart at a glance.

   Stage identity therefore travels on the CODE (S1..S5) and on the stage's own
   --colColor, which ui.js sets from that stage's completion. A category never
   holds more than five stages, so five steps is the whole ladder and there is
   no wrap to collide with. */

/* -------------------------------------------------------- 2. profile: hero */
/* ONE raised surface on the page. Everything that was a card beside it becomes
   a flat column under a hairline, which is what actually produces hierarchy —
   not more borders, fewer. */
.hero { gap: 22px; margin-bottom: 30px; align-items: stretch; }

.hero > .card.hero-id {
  background: var(--panel-2);
  border-color: var(--line-2);
  border-radius: var(--r-lg);
  padding: 24px 26px;
  box-shadow: 0 1px 0 color-mix(in srgb, #fff 6%, transparent) inset,
              0 8px 26px -14px rgba(0, 0, 0, 0.55);
}
:root[data-theme="light"] .hero > .card.hero-id {
  box-shadow: 0 10px 26px -18px rgba(31, 52, 66, 0.35);
}

/* Attributes and Record: supporting data, so they stop pretending to be
   objects. A rule instead of a frame. */
.hero > .card:not(.hero-id) {
  background: transparent;
  border: 0;
  border-top: 2px solid var(--line-2);
  border-radius: 0;
  padding: 14px 0 0;
  box-shadow: none;
}

.hero-name { font-size: 29px; letter-spacing: -0.03em; }
.hero-role { font-size: 13.5px; }
.xp-lvl b { font-size: 40px; letter-spacing: -0.04em; }
.xp-row { margin-top: 22px; }
.xp-track { height: 11px; }

/* The eyebrow is the only label these two columns get, so it has to hold. */
.hero > .card:not(.hero-id) .eyebrow {
  font-size: 11px; color: var(--txt-2); letter-spacing: 0.18em;
  margin-bottom: 16px !important;
}

.attr-grid { gap: 13px; }
.attr-row { grid-template-columns: 84px 1fr 38px; }
.attr-row .tr { height: 8px; border-radius: 3px; }
.attr-row .fl { border-radius: 3px; }

/* The record tiles were four framed boxes inside a framed card inside a framed
   row. Now: four figures on a ruled grid. */
.stat-tiles { gap: 0; }
.tile {
  background: transparent; border: 0; border-radius: 0;
  padding: 12px 14px 12px 0;
  border-bottom: 1px solid var(--line);
}
.stat-tiles > .tile:nth-child(odd) { padding-left: 0; }
.stat-tiles > .tile:nth-child(even) {
  padding-left: 14px; border-left: 1px solid var(--line);
}
.stat-tiles > .tile:nth-child(n + 3) { border-bottom: 0; }
.tile .v { font-size: 30px; }
.tile .k { margin-top: 5px; }

/* ------------------------------------------- 2b. profile: the section break */
/* "Skill Tracks" was a heading the same size as the one on every other screen,
   sitting in the same flow as the hero. It is the point of the page, so it
   gets a break above it. */
.page-head { position: relative; margin-top: 34px; padding-top: 24px; }
.page-head::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, var(--accent) 0 96px, var(--line) 96px 100%);
}
.page-head h1 { letter-spacing: -0.03em; }

/* Demote the sync banner. It is a condition, not the headline of the page —
   and it was the highest-contrast thing on every screen. */
.publish-banner {
  padding: 9px 12px !important;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--gold) 7%, transparent);
}
.publish-banner .t { font-size: 12px !important; }
.publish-banner .d { font-size: 11.5px !important; }

/* Same for the admin badge: a state, not a call to action. */
.toggle-master {
  background: transparent !important;
  color: var(--gold) !important;
  border: 1px solid color-mix(in srgb, var(--gold) 42%, transparent) !important;
}

/* Notifications: a strip, not a ninth card. */
.notif-card {
  background: transparent; border: 0; border-radius: 0;
  border-left: 3px solid color-mix(in srgb, var(--gold) 55%, transparent);
  padding: 10px 0 10px 14px !important;
}

/* ------------------------------------------------------ 2c. profile: tiles */
/* A track at rest is a square tile: what it is, how far along, and nothing
   else. Full-width rows spent the whole window on four figures and made the
   list read as a table of records; a grid of tiles reads as a set of things you
   can pick one of, which is what this list is for. */
.cat-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 14px;
}
.cat-tile {
  display: flex; flex-direction: column; justify-content: space-between;
  aspect-ratio: 1 / 1; min-height: 186px;
  padding: 18px; text-align: left; gap: 12px;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--panel); color: inherit;
  transition: border-color 0.15s, background 0.15s, transform 0.12s;
}
.cat-tile:hover {
  background: var(--panel-2); border-color: var(--line-2);
}
.cat-tile:active { transform: translateY(1px); }
.cat-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.ct-head { display: block; min-width: 0; }
.cat-tile .cat-name {
  font-size: 16px; font-weight: 650; letter-spacing: -0.015em; line-height: 1.25;
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
}
.ct-sub { display: block; font-size: 11.5px; color: var(--txt-3); margin-top: 5px; }

.ct-figs { display: block; }
/* The figure IS the tile's headline — it is the one thing being compared
   across the grid, so it is sized to be read from a scan, not hunted for. */
.ct-pct {
  display: block; font-family: var(--mono); font-size: 34px; font-weight: 700;
  letter-spacing: -0.04em; line-height: 1;
}
.ct-pct.none   { color: var(--tier-none-txt); }
.ct-pct.low    { color: var(--tier-low-txt); }
.ct-pct.mid    { color: var(--tier-mid-txt); }
.ct-pct.high   { color: var(--tier-high-txt); }
.ct-pct.legend { color: var(--tier-legend-txt); }

/* ONE bar. Not the pipeline in chunks — the total, as a length. */
.ct-bar {
  display: block; height: 10px; margin-top: 12px;
  border-radius: var(--r-sm); background: var(--track); overflow: hidden;
}
.ct-fill {
  display: block; height: 100%; border-radius: var(--r-sm);
  background: var(--fl, var(--accent));
  transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.ct-xp {
  display: block; font-family: var(--mono); font-size: 11px; color: var(--txt-3);
  margin-top: 8px;
}

/* ---------------------------------------- 2d. profile: the opened track head */
/* An open track has the page to itself, so its header is the page's subject
   line: the way back, what you are in, and the same three figures the tile
   carried — in the same order, so opening a tile does not feel like arriving
   somewhere else. */
.cat.open { background: transparent; border: 0; border-radius: 0; }
.cat-open-head {
  /* The name is the subject line, so it takes what it needs and the bar gets
     the remainder — the reverse of the first cut, where the name had 1fr and
     wrapped mid-phrase while a 12px-tall bar sat in 325px. */
  display: grid;
  grid-template-columns: auto minmax(max-content, auto) minmax(120px, 1fr) auto auto;
  gap: 18px; align-items: center;
  padding: 0 18px 16px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 18px;
}
.cat-open-head .cat-name { font-size: 19px; letter-spacing: -0.02em; white-space: nowrap; }
.cat-open-head .cat-sub { margin-top: 3px; }
.cat-open-bar .ct-bar { margin-top: 0; height: 12px; }
.cat-open-head .cat-pct { font-size: 30px; min-width: 78px; }
.cat-open-head .cat-xp { font-size: 13px; color: var(--txt-3); min-width: 108px; }
.cat-open-head .cat-xp b { color: var(--txt-2); }
@media (max-width: 900px) {
  .cat-open-head { grid-template-columns: auto minmax(0, 1fr) auto; }
  .cat-open-head .cat-name { white-space: normal; }
  .cat-open-bar { grid-column: 1 / -1; }
}

/* ------------------------------------------------ 3. timeline: stage identity */
/* A stage now has a name you can say out loud AND a code you can point at.
   The code is generated, so no markup changes: the axis row counts the cells,
   the column row counts the columns, and the two counts agree because the two
   rows are built from the same list of sections.

   Mastery colour is deliberately NOT touched here — .tl-seg-fill keeps its
   inline --segColor and .pip.on keeps its inline --pipColor. Identity and
   progress are now two channels that cannot be confused for each other. */
.tl-axis { counter-reset: stg; margin-top: 7px; }
/* The axis cell sits outside the column, so it has no --colColor of its own —
   the neutral fallback in .stg-code covers it. */
.tl-axis-cell { counter-increment: stg; }
/* Real-text variant, stamped by the optional patch-v2-stage-codes.js. Same
   look; the counters below cover it when that file is not loaded.

   Deliberately NEUTRAL, not tinted by the stage's colour. The stage's colour is
   its progress, and a code sitting in a wash of its own progress colour read as
   yellow-on-yellow at the very moment the code exists to be legible. The code
   identifies; the bar and the head rule carry the brand colour. */
.stg-code {
  font-family: var(--mono); font-size: 9px; font-weight: 700; letter-spacing: 0.04em;
  padding: 1px 5px; border-radius: 4px;
  color: var(--txt-2);
  background: var(--track);
}
.tl-axis-cell .stg-code { display: inline-block; margin-right: 7px; }
.tl-col-head .stg-code { display: inline-block; margin-bottom: 5px; }
.tl-axis-cell:has(.stg-code)::before,
.tl-col-head:has(.stg-code)::before { content: none; }

.tl-axis-cell::before {
  content: "S" counter(stg);
  display: inline-block; margin-right: 7px;
  font-family: var(--mono); font-size: 9px; font-weight: 700; letter-spacing: 0.04em;
  padding: 1px 5px; border-radius: 4px;
  color: var(--txt-2);
  background: var(--track);
}
.tl-axis-cell .w { display: inline; }

.tl-cols { counter-reset: stgc; margin-top: 16px; gap: 0; }
.tl-col { counter-increment: stgc; }

/* The column head carries the stage's own tone, and the code again, so a
   column can be identified without tracing a line back up to the bar. */
.tl-col-head {
  border-top: 3px solid var(--colColor);
  padding: 9px 10px 9px 0;
  margin-bottom: 10px;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--colColor) 15%, transparent) 0%,
    transparent 100%);
}
.tl-col-head::before {
  content: "S" counter(stgc);
  display: block; margin-bottom: 4px;
  font-family: var(--mono); font-size: 9px; font-weight: 700; letter-spacing: 0.06em;
  color: var(--txt-3);
}
.tl-col-title { font-size: 13px; }

/* No tone ladder. --colColor is ui.js's, i.e. the stage's own progress in the
   brand ramp, and the S-code is what identifies the stage. */

/* The bar reads as five stages, so it needs the gap to be unmistakable and the
   track to be quieter than the fill. */
.tl-bar { height: 34px; gap: 5px; }
.tl-seg { border-radius: 5px; }
.tl-seg .tl-seg-pct { font-size: 11px; }

/* Paging. The snap points are the STAGES, so a scroll settles on a column edge
   instead of halfway through one.

   proximity, and on the columns — NOT mandatory on .tl-inner. .tl-inner is the
   whole scroll content, so it offers exactly one snap point, at offset 0:
   mandatory snapping then drags every scroll back to the start and the stages
   past the fold become unreachable.

   No scroll-behavior here either. ui.js scrubs by assigning scrollLeft on every
   pointermove, and it restores the position by assigning it after a re-render —
   under smooth scrolling each assignment starts a fresh animation, so a drag
   never advances and the timeline visibly slides back into place every time a
   pip is clicked. Smoothness belongs on the paging control alone, where it is
   one scrollBy per press: see NEEDS-JS (1). */
.tl-scroll { scroll-snap-type: x proximity; }
.tl-col { scroll-snap-align: start; }
/* And the snap stands down for the length of a drag. Snapping is for where a
   gesture STOPS; quantising mid-gesture makes a hand-drag feel notched, because
   every pointermove gets pulled to the nearest column edge. ui.js already puts
   .scrubbing on the container for exactly this window. */
.tl-scroll.scrubbing { scroll-snap-type: none; }
.tl-wrap { padding: 0 18px 22px; }

/* The legend is the key to the whole colour language, so it stops being a
   footnote in --txt-3. */
.legend-row {
  margin-top: 16px; padding-top: 12px;
  border-top: 1px solid var(--line);
}
.legend-row .k { font-size: 11px; }
.legend-row .rank-key { color: var(--txt-2); }
.pip { width: 10px; height: 10px; }

/* --------------------------------------------------- 4. project admin: board */
/* The counters were the reason to open the screen and were set in 10px grey
   mono. They become the screen's status line. */
.notif-counts {
  font-family: var(--mono); font-size: 12px; color: var(--txt-2);
  font-variant-numeric: tabular-nums;
  padding: 7px 12px; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--panel);
}
.pa-n-review { color: var(--gold); }

/* The painter was a full-width card holding an empty select in the best
   position on the page. It is a mode, so it reads as a toolbar. */
.pa-painter {
  padding: 7px 10px; margin-bottom: 14px;
  background: transparent; border-style: dashed;
  border-radius: var(--r-sm);
}
.pa-painter.armed { background: color-mix(in srgb, var(--accent) 9%, transparent); border-style: solid; }
.pa-painter-lbl { font-size: 11px; text-transform: uppercase; letter-spacing: 0.12em; color: var(--txt-3); }
.pa-painter select { min-width: 220px; }
.pa-painter .help-note { font-size: 11px; margin: 0; }

/* A job is an object; its head should stay put while its scenes scroll past.
   The head now sits OUTSIDE the scroller, so it stays put by construction —
   `sticky` is kept because it costs nothing and still holds if the head is
   ever moved back inside. */
.pa-tile-head {
  position: sticky; top: 0; z-index: 2;
  background: var(--panel); border-bottom: 1px solid var(--line);
}
.pa-tile-name-h { font-size: 13px; letter-spacing: -0.01em; }

/* THREE STATES, three treatments — instead of one row treatment and a chip.
   free      dashed outline: the only state that invites a click
   taken     calm, no decoration, deliberately the quietest
   review    a gold edge, not a full wash — a wash on a third of the rows made
             the tile look like the alarm was the content

   RETARGETED. These were written against the earlier two-line row, where the
   states were `.ready` and `.taken` and the actions lived in `.pa-tile-acts`.
   The row is now one line with a pip rail, the waiting state is `.review`, and
   the actions are `.pa-tile-right`. The selectors are updated; the decisions
   are not — the gold EDGE in particular is the point of this block, and
   styles.css has been changed to stop drawing the wash rather than have the
   two files argue about it every render. */
.pa-tile-scene.free.armed .pa-tile-hit {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
.pa-tile-scene.review {
  background: transparent;
  box-shadow: inset 3px 0 0 var(--gold);
}
.pa-tile-scene.review:hover { background: color-mix(in srgb, var(--gold) 9%, transparent); }
.pa-tile-review { border-radius: 4px; letter-spacing: 0.1em; }

/* Deleting a whole scene sat at the same weight as approving one, on every
   row. It steps back until the row is under the cursor. The row's own ✕ is
   handled in styles.css, which hides it outright until hover. */
.mini-acts button.del { opacity: 0.35; transition: opacity 0.12s; }
.pa-tile-head:hover .mini-acts button.del { opacity: 1; }

.pa-group {
  font-size: 9.5px; letter-spacing: 0.14em; color: var(--txt-3);
  padding-top: 10px;
}

/* --------------------------------------- 4b. project admin: the assign screen */
/* Fourteen rows of three dropdowns is a form. Ruling it into rows and pushing
   the pickers back to secondary makes it a list you read, with controls on it. */
/* gap 0 so the rule under a row is continuous instead of breaking into five
   separate underlines with a 10px hole between each. The columns get their
   breathing room from cell padding, which the border follows. */
.pa-as-list { gap: 0; }
.pa-as-row > * { padding: 7px 10px 7px 0; }
.pa-as-row > *:last-child { padding-right: 0; }
.pa-as-row:not(.pa-group) > * { border-bottom: 1px solid var(--line); }
.pa-as-row:hover > * { background: color-mix(in srgb, var(--panel-2) 60%, transparent); }
.pa-as-name { font-size: 13px; }
.pa-as-row select.field {
  background: transparent; border-color: transparent;
  font-size: 11.5px; color: var(--txt-2);
}
.pa-as-row:hover select.field,
.pa-as-row select.field:focus { background: var(--panel); border-color: var(--line-2); }
.pa-as-hold { font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em; }

/* ============================================================================
   NEEDS-JS — three things CSS cannot do
   ----------------------------------------------------------------------------
   (1) FIVE STAGES A PAGE. layoutTimelines() currently sizes .tl-inner off the
       narrowest share. Size it so five stages fill the visible width instead:

           var perPage = 5;
           var visible = scroll.clientWidth;
           var shown   = segs.slice(0, perPage)
                             .reduce(function (a, s) { return a + s.widthPct; }, 0);
           inner.style.width = (visible * 100 / shown) + '%';

       The scroll-snap rules above then land each page on a stage boundary.
       Two arrow buttons on .tl-wrap calling scrollBy({left: clientWidth}) give
       it the paging control; nothing else changes.

   (2) THE STAGE CODE IN THE DATA. The codes here are generated by CSS counters,
       so they are positional: S3 is "the third stage of this track". That is
       correct and stable for reading, but a code cannot then be quoted in a
       comment or a filename. If you want that, put an index on the section in
       renderTimeline()/renderColumn() (data-stg="3") and swap the two
       counter() rules for attr(data-stg).

   (3) PIPELINE POSITION ON A SCENE ROW. paSceneState() returns stageName only,
       so a row can say "Texturing" but not "4 of 9". Return the index and the
       length too and the row can carry a position — the one piece of
       information the board is missing rather than mis-styling.
   ========================================================================== */
