/* ===========================================================================
   Activities of SDTD — register and entry styles.
   Extracted with js/activities.js.

   Two token sets are in play, on purpose. Layout and brand come from the shared
   palette in index.html :root (Palette B — steel blue, D-037), so --accent still
   changes with the palette switcher. Everything structural — header fill, row
   rules, frozen-column seams, field edges — comes from the neutral scale
   --n0…--n900 plus --edge and --hair, which the palette blocks do not touch.
   That is what makes this surface hold together at 15 columns: the only colour
   left in the grid is status colour, so red/amber/green read as meaning rather
   than as decoration.

   Rules of the set: 4px spacing step, type only at 11/12/13/16px, every figure
   tabular, one hairline weight (--hair, halved above 2dppx), and no border on an
   interactive control lighter than --edge.

   Selectors are prefixed .ar- (activity register) or .ek-drawer so they cannot
   collide with the shared component classes in index.html.
   =========================================================================== */

/* ---- toolbar: search, archive/rows-per-page, dropdown filters ----
   The chip strip (one pill per column, doubling as its visibility toggle and
   its filter trigger) and the "Conditions:" bar that sat under it are gone as
   of the reference-style redesign — replaced by the plain per-column
   <select>s below and the "My views" pill row in .ar-views (§ further down,
   emitted by arViewsRowHtml() inside the refreshed host, since it is buttons
   rather than native form controls). The column chooser those chips also
   doubled as is gone too: the table is one fixed column set now
   (AR_DISPLAY_KEYS in js/activities.js), not something an officer configures. */
.ar-bar{display:flex;flex-direction:column;gap:8px;margin-bottom:12px}
.ar-searchrow{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
/* #activity-search used to sit in .activity-toolbar, which is what gave it its
   width (index.html:597). It is in .ar-searchrow now, so that rule no longer
   matches and the box would collapse to the browser default. */
.ar-bar .search{min-width:232px;flex:1;max-width:392px}
.ar-bar .field{border-color:var(--edge)}
/* Two rows of plain dropdowns, one condition each — see AR_FILTER_ROWS. Each
   is a native <select> rendered by arBarHtml(), outside the refreshed host,
   for the same reason the archive and rows-per-page selects already were:
   arRefresh() only ever replaces #activity-register-host, and a select
   destroyed mid-navigation cannot be walked past its second option in
   Firefox or Safari (see the long comment above arBarHtml in js/activities.js). */
.ar-filters{display:flex;gap:8px;flex-wrap:wrap}
.ar-filters2{margin-bottom:4px}
.ar-fld{position:relative;flex:1;min-width:160px}
.ar-fld select{width:100%;appearance:none;border:var(--hair) solid var(--edge);border-radius:6px;background:var(--n0);color:var(--n700);font:inherit;font-size:12px;padding:8px 28px 8px 12px;cursor:pointer}
.ar-fld select:hover{border-color:var(--n700)}
.ar-chev{position:absolute;right:12px;top:50%;transform:translateY(-50%);font-size:11px;color:var(--n500);pointer-events:none}

/* ---- "My views" pills and the one quick filter ----
   Buttons, not a <select> — unlike the toolbar controls above, these are safe
   to live inside #activity-register-host and be rebuilt on every arRefresh(),
   which is what lets a pill's pressed state and its live row count
   (arViewCount) track arConds without any of the arSyncFilterSelects()
   machinery the plain filters need. */
.ar-views{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:12px}
.ar-views-label{font-size:11px;font-weight:700;letter-spacing:.04em;color:var(--n500)}
.ar-view-pill{border:var(--hair) solid var(--edge);border-radius:6px;padding:8px 12px;font-size:12px;font-weight:600;line-height:1.2;background:var(--n0);color:var(--n600);cursor:pointer}
.ar-view-pill:hover{border-color:var(--n700);color:var(--n900)}
.ar-view-pill.on{background:var(--accent-dim);border-color:var(--accent);color:var(--accent)}
.ar-quick{margin-left:auto;border:var(--hair) solid var(--red-ink);border-radius:6px;padding:8px 12px;font-size:12px;font-weight:700;line-height:1.2;background:var(--n0);color:var(--red-ink);cursor:pointer}
.ar-quick:hover{background:var(--red-bg)}
.ar-quick.on{background:var(--red-ink);border-color:var(--red-ink);color:#fff}

/* ---- topic badges: GROUP, an open change request, CRITICAL ----
   Additive to the existing .ar-pending marker (below, under "the grid"), not
   a replacement for it — Assignment and Criticality are filterable but no
   longer columns of their own in the fixed 8-column table, so the one flag
   worth repeating next to the topic itself is surfaced here instead. */
.ar-badges{display:flex;gap:4px;flex-wrap:wrap;margin-top:4px}
.ar-badge{display:inline-flex;align-items:center;font-size:11px;font-weight:700;letter-spacing:.02em;border-radius:4px;padding:4px 8px;border:var(--hair) solid}
.ar-badge.ar-b1{border-color:var(--accent);color:var(--accent)}
.ar-badge.ar-b2{border-color:var(--amb-ink);color:var(--amb-ink);background:var(--amb-bg)}
.ar-badge.ar-b3{border-color:var(--red-ink);color:var(--red-ink);background:var(--red-bg)}

/* ---- the grid ----
   The scrollport is here, not on the page, and that is a deliberate trade. A
   table this wide has to scroll sideways, and the box that scrolls sideways is
   the only box that can also pin the header — position:sticky resolves against
   the nearest scrolling ancestor. Let the page scroll instead and you keep one
   scrollbar but lose the header at row 15, which on a register whose columns are
   six near-identical date and name fields is the more expensive loss.
   min() with dvh so it tracks the mobile toolbar, and a px fallback first for
   engines without dvh. 900px caps it on a tall desktop monitor, where an
   800px-tall grid would push the footer count off screen. */
.ar-wrap{overflow:auto;-webkit-overflow-scrolling:touch;border:var(--hair) solid var(--n300);border-radius:8px;background:var(--n0);max-height:640px;max-height:min(85dvh,900px)}
/* min-width:max-content, not the old fixed min-width:1800px: the table is only
   as wide as the columns actually shown, and .ar-wrap scrolls when there are
   enough of them. With width:100% alone, 15 columns would cram instead. */
.ar-table{width:100%;min-width:max-content;border-collapse:separate;border-spacing:0;font-size:12px;color:var(--n900)}
/* height and line-height are pinned. The seam under the header is a
   box-shadow, not a border: a border-bottom on a sticky th is painted at the
   th's own edge and separates from the scrolling body by a subpixel at
   fractional zoom, which shows as a flickering gap.
   There used to be a second sticky row here — the per-column ▾ slicers, in
   their own <tr class="ar-slicers"> pinned at top:32px — which is also why
   height was pinned to begin with (so the two rows' offsets could not drift
   apart). The slicers now live in the chip strip above the table (§7 in
   js/activities.js), one <tr> does the whole header, and this rule keeps its
   fixed height only because a table header benefiting from one is reason
   enough on its own. */
.ar-table th{position:sticky;top:0;z-index:3;background:var(--n50);color:var(--n700);text-align:left;text-transform:none;letter-spacing:0;font-size:11px;line-height:1.2;font-weight:600;height:32px;box-sizing:border-box;border-bottom:0;box-shadow:inset 0 calc(-1 * var(--hair)) 0 var(--n300);padding:8px 12px;white-space:nowrap}
.ar-table td{padding:8px 12px;white-space:nowrap;border-bottom:var(--hair) solid var(--n200);vertical-align:top}
.ar-table td.ar-topic{white-space:normal;min-width:240px;font-weight:600}
/* ---- column widths ----
   Two rules, and they only make sense together.

   The problem they fix, stated correctly: .ar-table carries BOTH width:100% and
   min-width:max-content, and the second one wins whenever the columns' natural
   widths exceed the panel. max-content lays a cell out with no wrapping at all --
   that is what max-content MEANS, regardless of white-space -- so a column's
   contribution is its longest single value on ONE line: a 120-character topic
   contributed roughly 700px, matching the ~740px measured in the report, and
   Assigned To printed all six members of a group as
   "Name — Designation" for another few hundred. min-width:max-content then forced
   the table wider than the panel and everything after Topic went off-screen.

   So rule 2 below is the fix and rule 1 is the finish. Not the other way round:
   while min-width:max-content is the winning constraint the table is wider than
   its panel, there is no surplus, and a width:100% cell has nothing to absorb.

   1. The trailing Actions column absorbs the surplus, in the case where the shown
   columns DO fit -- a wide monitor, or a few columns toggled on. width:100% on the
   last cell is a table-layout:auto idiom: that column claims the remaining space,
   which leaves every data column at its own content width instead of stretching
   the elastic one. The buttons stay left-aligned, so the slack reads as empty
   space at the right. It applies to the last cell of every row, header rows
   included, so the three rows stay in step. Keep it at exactly 100%: a smaller
   percentage would inflate the table's own max-content minimum and reintroduce
   horizontal scroll.

   2. A ceiling on the free-text columns, so one unusually long value cannot widen
   its column for every row. max-width on a table cell is unreliable in auto
   layout -- the used value is advisory and engines disagree -- so arGridHtml wraps
   the content of any column carrying a `w` descriptor in .ar-cw and the ceiling
   goes on that. Bounding the CONTENT bounds the column's max-content contribution,
   which is what the table's sizing algorithm actually reads.

   A cap is not a licence to render an unbounded string, though: capping Assigned
   To turned a 230-character group roster into a nine-line cell, so that column now
   renders a summary and its cap only has to hold a group name. Where the value
   itself is unbounded, fix the renderer; the cap is for the ordinary long case.

   The ceilings are in ch, not px, so they track the font rather than a guess about
   it. A ch is the '0' advance, ~0.60em in DM Sans against ~0.48em for average
   mixed-case text, so Nch holds roughly 1.24N characters -- the caps are looser
   than they look, not tighter.

   Each one is derived from the longest real value in that column AS IT IS NOW
   RENDERED, which is not the same as the longest value in the data. Assigned To
   shows an officer name for an individual (34 characters at most, "Chinta Siva
   Santosh Dharma Kowshik") but a GROUP NAME for a group, and those are longer:
   "Group 3 — Architecture & Coordination" is 37, so the cap is 32ch, not 28.
   Assigned By is always "Name — Designation" and the longest sanctioned assigner
   is 36 ("Rishi Sumeet Kumar — GM (Technology)"), on one line at 30ch. Activity
   types
   reach 36 characters
   ("Knowledge Management & Documentation") and categories 35 ("Architecture, Cloud
   & Cybersecurity"), so 24ch wraps the worst of them to two lines and leaves the
   median 25 on one. Topics in the live register run 48-65 characters, so 46ch is
   two lines at the top of that range. Two lines, not one with an ellipsis: a
   truncated topic is unreadable and the officer cannot tell two similar activities
   apart, which is the whole job of that column. */
/* `.ar-table tr>:last-child{width:100%}` was here and has been REMOVED. Measured in
   Chrome against the deployed build, that one declaration was the cause of the original
   "the width of the columns are not optimised" report, and every round of ch-tuning that
   followed was treating a symptom.
   Why: a percentage width on a cell of a table that is itself sized at
   min-width:max-content feeds back into the table's own width, and the layout runs away to
   Chrome's internal table-width cap. Measured, with the same single row: table 500000px
   wide, last column 499190px, Topic squeezed to 54px. With this declaration gone: table
   1398px, last column 65px, Topic 372px. Nothing else changed between the two numbers.
   The reason the columns then looked "crushed" rather than merely wide is that once the
   runaway consumes the table, every other column falls to its MIN-content, and min-content
   under the overflow-wrap:anywhere below is a single character -- hence names rendering one
   letter per line.
   Do not reintroduce it. A trailing column that must absorb slack needs table-layout:fixed
   and a colgroup, which is what #completion-register now uses in index.html. */

.ar-table td .ar-cw{max-width:var(--cw);white-space:normal;overflow-wrap:break-word;overflow-wrap:anywhere}
/* Anything the cell renderers deliberately keep on one line stays on one line:
   the change-request marker, status markers, pills and dates are short and read as
   single tokens. Only the prose wraps. Of these, only .ar-pending (on Topic) can
   match today -- .mono, .pill and .ar-state live in columns that carry no `w`. The
   other three are kept deliberately so that adding a `w` to one of those columns
   later cannot break its token; if you remove them, check that first. */
.ar-table td .ar-cw .ar-pending,.ar-table td .ar-cw .mono,
.ar-table td .ar-cw .pill,.ar-table td .ar-cw .ar-state{white-space:nowrap}
/* An ellipsis needs a block-ish box, so these get inline-block -- but NOT .ar-state,
   which is inline-flex with a ::before status dot sized 8x8. width and height do not
   apply to a non-replaced inline box and gap does not apply to a non-flex container,
   so inline-block there would silently erase the dot and its spacing. It keeps its
   display and clips instead. */
.ar-table td .ar-cw .ar-pending,.ar-table td .ar-cw .mono,
.ar-table td .ar-cw .pill{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.ar-table td .ar-cw .ar-state{max-width:100%;overflow:hidden}
/* Amber, not red: an open change request is a normal state of the workflow, not a
   failure. Weight drops to 400 so it reads as an annotation on the bold topic
   rather than part of the title. */
.ar-table td.ar-topic .ar-pending{display:inline-block;margin-left:6px;padding:0 4px;border-radius:4px;
  background:var(--amb-bg);color:var(--amb-ink);border:1px solid #eddcb8;
  font-size:11px;font-weight:400;letter-spacing:.02em;white-space:nowrap;vertical-align:1px}
.ar-table tbody tr:hover td{background:var(--n25)}
/* the header button carries the whole cell so the click target is the cell, not
   the word — a 44px-wide "PCT" header with a 28px target is a miss most times */
.ar-table th .ar-hd{display:flex;align-items:center;gap:4px;width:100%;min-height:24px;margin:-8px -12px;padding:8px 12px;border:0;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer}
.ar-table th .ar-hd:hover{color:var(--n900)}
.ar-table th .ar-caret{font-size:11px;color:var(--accent)}
.ar-table th[aria-sort="ascending"],.ar-table th[aria-sort="descending"]{color:var(--n900);background:var(--n100)}
/* The frozen seam is a shadow for the same reason as the header seam, and it is
   inset so it cannot bleed over the neighbouring cell's text. */
.ar-table .ar-f1{position:sticky;left:0;z-index:2;background:var(--n0);box-shadow:inset calc(-1 * var(--hair)) 0 0 var(--n200)}
.ar-table .ar-f2{position:sticky;left:148px;z-index:2;background:var(--n0);box-shadow:inset calc(-1 * var(--hair)) 0 0 var(--n300)}
/* .ar-f2's left: is only correct if column 0 has a fixed width. arGridHtml adds
   .ar-idfirst exactly when column 0 is the Activity ID, which is mono and always
   SDTD-ACT-YYYY-NNNN, so 148px holds. */
.ar-table.ar-idfirst th.ar-f1,.ar-table.ar-idfirst td.ar-f1{width:148px;min-width:148px;max-width:148px}
/* box-shadow is one property, not two, so the frozen rule below REPLACED the
   header's bottom seam rather than adding to it — the hairline under the
   heading row simply stopped at the frozen columns, so this has to name both
   shadows. */
.ar-table th.ar-f1,.ar-table th.ar-f2{z-index:4;background:var(--n50);box-shadow:inset calc(-1 * var(--hair)) 0 0 var(--n300),inset 0 calc(-1 * var(--hair)) 0 var(--n300)}
/* and the sort tint has to be restated here: .ar-table th.ar-f1{background} and
   .ar-table th[aria-sort]{background} are both (0,2,1), so the later one wins and
   the frozen column was the one column that showed no sorted state. */
.ar-table th.ar-f1[aria-sort="ascending"],.ar-table th.ar-f1[aria-sort="descending"],
.ar-table th.ar-f2[aria-sort="ascending"],.ar-table th.ar-f2[aria-sort="descending"]{background:var(--n100)}
.ar-table tbody tr:hover .ar-f1,.ar-table tbody tr:hover .ar-f2{background:var(--n25)}
/* index.html:703 sets tr.archived td{opacity:.58;background:#f4f5f7} at (0,1,2).
   Overriding only colour left both of those in place, and opacity on a sticky
   cell makes the frozen column translucent — body cells scrolled visibly through
   it. Restate both, and repeat the fill on the frozen cells, which otherwise keep
   the white from .ar-table .ar-f1 at equal specificity. */
.ar-table tr.archived td{color:var(--n500);font-style:italic;opacity:1;background:var(--n50)}
.ar-table tr.archived .ar-f1,.ar-table tr.archived .ar-f2{background:var(--n50)}
.ar-table tbody tr.archived:hover td,.ar-table tbody tr.archived:hover .ar-f1,.ar-table tbody tr.archived:hover .ar-f2{background:var(--n100)}
.ar-table .mono,.ar-table .num{font-variant-numeric:tabular-nums}

/* ---- status as a marker plus the word ----
   Not a pill. A filled pill is the loudest object a table cell can hold, and
   with one in every row of the status column the eye is drawn to all of them
   equally, which is the same as none. An 8px square in the status colour plus
   the word in text ink puts the colour where it is scanned and leaves the row
   readable. Square, not round: the round dot reads as a live indicator light. */
.ar-state{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:500;color:var(--n700);white-space:nowrap}
.ar-state:before{content:'';width:8px;height:8px;border-radius:2px;flex:none;background:currentColor}
.ar-state.ar-s-run{color:var(--amb-ink)}
.ar-state.ar-s-ok{color:var(--grn-ink)}
.ar-state.ar-s-stop{color:var(--red-ink)}
/* --n500 (#667085, 4.97:1 on white), NOT --idle. A review asked for these to be the same value as
   the progress bar's fill; they cannot be. --idle (#8794a7) is 3.08:1, which is fine for a fill —
   graphics need 3:1 — and fails the 4.5:1 that this marker's TEXT needs. The two greys differ on
   purpose, and this is the one place in the tone set where the pair is split. */
.ar-state.ar-s-idle{color:var(--n500)}
/* the marker carries the colour; the word stays ink so the row reads normally */
.ar-state span{color:var(--n700)}

/* .trk is width:46px;flex:none, so the bar and the figure need a flex parent.
   The flex box is a span inside the td — never the td itself, because
   display:flex on a table cell drops it out of the column grid. */
.ar-prog{display:flex;align-items:center;gap:8px}
.ar-prog .mono{font-size:11px}
.ar-empty{padding:24px 16px;text-align:center;color:var(--n500);font-size:12px;line-height:1.6}
.ar-empty b{color:var(--n900)}
.ar-foot{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-top:8px;font-size:11px;color:var(--n500);flex-wrap:wrap}
.ar-foot b{color:var(--n900);font-variant-numeric:tabular-nums}

/* ---- pager. Sits under the footer line: grid, then what you are looking at,
        then how to move through it. ---- */
.ar-pager{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:8px}
.ar-page{min-width:28px;height:28px;padding:0 8px;border:var(--hair) solid var(--n300);border-radius:4px;
  background:#fff;color:var(--n700);font-size:12px;font-variant-numeric:tabular-nums;cursor:pointer}
.ar-page:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}
.ar-page:disabled{opacity:.45;cursor:default}
/* Current page carries a border and weight as well as fill, so it is not colour alone. */
.ar-page.on{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}
.ar-page:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.ar-gap{padding:0 4px;color:var(--n500);font-size:12px}
.ar-page-of{margin-left:4px;font-size:11px;color:var(--n500);font-variant-numeric:tabular-nums}
.ar-page-size{display:inline-flex;align-items:center;gap:4px;margin-right:8px;font-size:11px;color:var(--n500)}
.ar-page-size .field{height:28px;padding:0 8px;font-size:12px;width:auto}

/* ---- quick-add drawer. The panel IS the #activity-entry form, so every
        existing helper (editSdtActivity, toggleActivityEntry, updateAssignmentTarget,
        renderGroupMemberPicker, addSdtActivity) keeps working unchanged. ---- */
/* overflow:clip, not hidden. hidden makes .ek-stage a programmatically
   scrollable container, and editSdtActivity/createGroupAssignment/
   createSpecialAssignment all call form.scrollIntoView() while the drawer is
   still mid-transform and up to 416px past the right edge — which scrolled the
   grid off-screen with no scrollbar to get it back. clip cannot scroll.
   min-height so the drawer is usable on a short or empty register: without it
   the stage is as tall as its content, and on the first-run empty state — the
   exact moment a new user opens the drawer — 15 fields got ~140px of scroll.
   2026-08-29: clipping BOTH axes amputated the drawer. The drawer is absolutely
   positioned, so it adds nothing to the stage's height; once assignmentType,
   assignedTo and the member picker joined the always-visible block the collapsed
   drawer outgrew min-height:560px, and .ek-dfoot — Cancel and Save — was the
   bottom-most band, so it was the first thing cut off. No scrollbar appeared
   either, because the drawer was still well under its own 85dvh cap, so nothing
   hinted the buttons existed. Only the horizontal axis needs clipping (the
   closed drawer is parked 416px past the right edge); the vertical axis is
   `visible`, so a tall drawer spills below the stage and ordinary page scroll
   reaches Save. overflow-x:clip + overflow-y:visible creates no scroll container
   at all, which is what keeps the scrollIntoView problem above fixed. */
.ek-stage{position:relative;overflow-x:hidden;overflow-x:clip;overflow-y:visible;border-radius:8px;min-height:560px}
.ek-grid{transition:margin-right .2s ease}
/* 2026-09-07, first attempt: the drawer used to slide in from the right and share
   the stage's own layout box (margin-right:400px made room for it). Restyled as a
   centered wide modal by giving form.ek-drawer its own position:fixed + a
   translate(-50%,-50%) centering hack — which rendered off-center, because the
   drawer is still a normal descendant of .ek-stage/.ek-grid/.card/#view, and
   position:fixed is only reliably viewport-relative when NO ancestor establishes a
   containing block of its own (a transform, filter, perspective, contain or
   will-change anywhere in that chain retargets it). Chasing down which ancestor
   was responsible was the wrong fight — the app already has a proven, working
   centered-overlay pattern (openActivityTile, openAddSpocModal): a NEW element
   appended directly to document.body, escaping every ancestor entirely.
   2026-09-07, second attempt: the drawer is created fresh into such an overlay by
   ensureActivityEntryOverlay() (index.html) whenever it opens, instead of being
   permanently embedded in arStageHtml()'s markup. form.ek-drawer now carries the
   same .pf-modal.wide classes the activity detail tile uses, so its background,
   border, radius, shadow, width and mobile full-bleed-sheet behaviour all come
   from that already-proven CSS for free — nothing bespoke to get wrong twice.
   The grid no longer needs to make room for it; a fixed overlay needs no layout
   space reserved beside it. */
form.ek-drawer{display:flex;flex-direction:column;max-height:min(88vh,820px)}
.ek-drawer .ek-dhead{padding:12px 16px;border-bottom:var(--hair) solid var(--n200);display:flex;justify-content:space-between;align-items:flex-start;gap:8px}
.ek-drawer .ek-dhead .t1{color:var(--n900)}
.ek-drawer .ek-dhead .t2{font-size:11px;color:var(--n500)}
.ek-drawer .ek-dscroll{overflow:auto;padding:16px;flex:1;display:flex;flex-direction:column;gap:12px}
/* Descendant, not child: five fields are direct children of .ek-dscroll — the
   rest live inside the two <details> bodies, and with `>` they fell back to a
   default inline <label>, caption and control on one line. The old form got its
   column layout from `.activity-form-grid label`, which no longer applies
   because that class is gone from the drawer. */
.ek-drawer .ek-dscroll label{display:flex;flex-direction:column;gap:4px;font-size:11px;color:var(--n600);font-weight:600;letter-spacing:.03em;text-transform:uppercase}
/* …but a descendant selector also swallowed the officer checkboxes. The picker
   emits <label class="grp-mem"> (index.html:685 styles it inline-flex at 12.5px; 13px here, to stay on the type ramp),
   and this rule is (0,2,1) against that rule's (0,1,0) in a stylesheet that
   loads later, so every officer rendered as a stacked uppercase 11px block with
   the checkbox on its own line above the name. Put the pill back. */
.ek-drawer .ek-dscroll label.grp-mem{display:inline-flex;flex-direction:row;align-items:center;gap:6px;font-size:13px;font-weight:400;letter-spacing:0;text-transform:none;color:var(--n700)}
.ek-drawer .ek-dscroll label .t2{text-transform:none;letter-spacing:0;font-weight:400;color:var(--n500)}
/* index.html scopes this to `.activity-form-grid .field`, also gone. */
.ek-drawer .ek-dscroll .field{width:100%;box-sizing:border-box;border-color:var(--edge);font-size:13px;color:var(--n900)}
.ek-drawer .ek-dscroll .field::placeholder{color:var(--n500)}
.ek-drawer .ek-dscroll optgroup{font-size:11px;color:var(--n500);font-style:normal;font-weight:600}
.ek-drawer .ek-dscroll optgroup option{font-size:13px;color:var(--n900);font-weight:400}
.ek-drawer .ek-dfoot{padding:12px 16px;border-top:var(--hair) solid var(--n200);background:var(--n50);display:flex;justify-content:flex-end;gap:8px}
.ek-drawer .ek-dhint{font-size:11px;color:var(--n500);line-height:1.5}
.ek-drawer details > summary{cursor:pointer;font-size:12px;font-weight:600;color:var(--accent);list-style:none;min-height:24px;display:flex;align-items:center;gap:4px}
.ek-drawer details > summary::-webkit-details-marker{display:none}
.ek-drawer details > summary:after{content:'▾';font-size:11px}
.ek-drawer details[open] > summary:after{content:'▴'}
.ek-drawer details .ek-dbody{display:flex;flex-direction:column;gap:12px;padding-top:12px}
.ek-drawer #group-member-picker{max-height:168px;overflow:auto}
.ek-drawer #group-member-picker:empty{display:none}
/* updateAssignmentTarget() and renderGroupMemberPicker() toggle a `hidden`
   class, but the inline stylesheet only ever defined .hidden for two specific
   components, so the toggle was a no-op. Honour it inside the drawer. */
.ek-drawer .hidden{display:none}

/* ---- narrow screens: the drawer becomes full width and the grid stops shifting ---- */
/* 768px, matching every other breakpoint in index.html. At 900 the drawer went
   full-width while .ek-grid still had margin-right:0, so it covered the grid
   before any of the touch-target rules had engaged. */
@media(max-width:768px){
  .ar-bar .search{max-width:none;width:100%}
  .ek-stage{min-height:0}
  /* No drawer-specific override needed here any more: form.ek-drawer carries
     .pf-modal.wide, and .pf-modal's OWN mobile rule (index.html) already turns
     every such modal into a full-bleed bottom sheet (max-width:100%, its own
     max-height, border-radius flattened on top) — one rule, reused, rather than
     a second copy of it living here and risking drifting out of step. */
  /* index.html:829 sets .field{font-size:16px} under this breakpoint precisely to
     stop iOS Safari zooming on focus, and the drawer's own 13px rule (0,3,0) was
     beating it. */
  .ek-drawer .ek-dscroll .field{font-size:16px}
  /* the register's own controls are the only ones the page's 44px touch-target
     rules never reached — they are not .btn and not .field. The view pills and
     the quick-filter button replaced the chip strip and its slicer, which is
     what this rule used to reach; the plain filter <select>s already use
     .field and are covered by index.html's own mobile rule for it. */
  .ar-view-pill,.ar-quick{min-height:44px}
  /* index.html:810 relaxes .activity-table-wrap the same way: a nested vertical
     scroller inside page scroll, with a sticky header row and a 148px frozen
     column on a 360px viewport, is a scroll trap. Sideways scroll stays. */
  .ar-wrap{max-height:none}
  .ar-table .ar-f1,.ar-table .ar-f2{position:static;box-shadow:none}
  .ar-table th.ar-f1,.ar-table th.ar-f2{position:sticky;left:auto}
  .ar-table.ar-idfirst th.ar-f1,.ar-table.ar-idfirst td.ar-f1{width:auto;min-width:0;max-width:none}
}

/* Focus ring, declared last so it beats the per-element border-radius and
   background rules above rather than racing them. Two pixels of accent on a
   2px offset is visible on every fill in the neutral scale, which a 1px
   --edge outline is not. */
.ar-view-pill:focus-visible,.ar-quick:focus-visible,.ar-fld select:focus-visible,
.ar-table th .ar-hd:focus-visible,
.ek-drawer details > summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:6px}
.ar-table th .ar-hd:focus-visible{outline-offset:-2px}
@media (prefers-reduced-motion:reduce){
  .ek-grid,form.ek-drawer,form.ek-drawer.activity-entry{transition:none}
}

/* ---- activity pipeline ----
   A second reading of the register: grouped rows, not a new table.
   Status colours are fixed on purpose. They mean the same thing on every
   palette, while the header still follows --accent. */
.ap-toolbar{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:12px}
.ap-toolbar label{font-size:11px;font-weight:700;color:var(--n600,#4a5567)}
.ap-toolbar .field{min-width:180px}
.ap-toolbar input.field{flex:1;max-width:280px}
.ap-legend{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:14px;font-size:11px;color:var(--dim,#5a6879)}
.ap-legend span{display:inline-flex;align-items:center;gap:6px}
.ap-dot{width:10px;height:10px;border-radius:2px;display:inline-block}
.ap-dot.ap-draft,.ap-pill.ap-draft{background:#f97316}
.ap-dot.ap-run,.ap-pill.ap-run{background:#eab308}
.ap-dot.ap-risk,.ap-pill.ap-risk{background:#dc2626}
.ap-dot.ap-closed,.ap-pill.ap-closed{background:#2563eb}
.ap-dot.ap-hold,.ap-pill.ap-hold{background:#94a3b8}
.ap-wrap{border:1px solid #94a3b8;border-radius:2px;overflow:auto}
.ap-table{width:100%;border-collapse:collapse;table-layout:fixed;min-width:880px}
.ap-c-name{width:28%}.ap-c-owner{width:18%}.ap-c-days{width:12%}.ap-c-status{width:16%}.ap-c-pri{width:10%}.ap-c-note{width:16%}
.ap-table thead th{background:var(--accent,#1c4f7c);color:#fff;font-size:11px;font-weight:650;text-align:left;padding:8px 12px;border-right:1px solid rgba(255,255,255,.18)}
.ap-table thead th:last-child{border-right:none}
.ap-table thead th.ap-num{text-align:right}
.ap-table tbody td{padding:8px 12px;border-right:1px solid #cbd5e1;border-bottom:1px solid #cbd5e1;vertical-align:middle;font-size:12px;background:#fff}
.ap-table tbody td:last-child{border-right:none}
.ap-table tbody tr.ap-data:hover td{background:#f8fafc}
.ap-table tr.ap-grp td{background:var(--accent-dim,rgba(28,79,124,.10));font-weight:700;font-size:12px;color:var(--accent,#1c4f7c);padding:8px 12px;border-bottom:1px solid #93c5fd}
.ap-table tr.ap-sum td{background:#f1f5f9;font-weight:650;font-size:12px;border-bottom:1px solid #cbd5e1}
.ap-lbl{color:var(--n600,#4a5567)}
.ap-days,.ap-val{text-align:right;font-variant-numeric:tabular-nums;font-weight:650}
.ap-open{display:block;width:100%;padding:0;border:0;background:none;text-align:left;color:inherit;cursor:pointer;font:inherit}
.ap-open:focus-visible{outline:2px solid var(--accent,#1c4f7c);outline-offset:2px;border-radius:4px}
.ap-task{display:block;font-weight:650;color:var(--n900,#101828);line-height:1.35}
.ap-id{display:block;font-family:var(--mono,ui-monospace,monospace);font-size:11px;color:var(--n500,#667085);font-weight:500;margin-top:4px}
.ap-owner{display:flex;align-items:center;gap:10px;min-width:0}
.ap-av{width:32px;height:32px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#fff;letter-spacing:-.02em}
.ap-owner-name{font-weight:500;font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ap-note{color:var(--dim,#5a6879);font-size:11px;line-height:1.4}
.ap-pill{display:inline-block;font-size:11px;font-weight:700;letter-spacing:.02em;padding:4px 8px;border-radius:4px;white-space:nowrap;text-align:center;min-width:88px;color:#fff}
.ap-pill.ap-run{color:#1a2332}
.ap-pill.ap-pri-h{background:#ea580c;color:#fff}
.ap-pill.ap-pri-m{background:var(--accent,#1c4f7c);color:#fff}
.ap-pill.ap-pri-l{background:#e2e8f0;color:#475569}
.ap-n-late{color:var(--amb-ink,#c2410c)}
.ap-n-ytd{color:var(--grn-ink,#15803d)}
.ap-foot{margin-top:12px;font-size:11px;color:var(--dim,#5a6879);max-width:78ch}
