/* Tactics — the writer's index panel on the Team Documents page, and the article page.
   Shared by both, because the index renders on one and the images on the other and neither
   justifies a second stylesheet. */

/* --------------------------------------------------------------------------------------
   The Documents page's two right-hand panels.

   [hidden] ALONE DOES NOT HIDE A .gp-card. The attribute works through the UA's
   [hidden] { display: none }, which ANY author `display` beats — and .gp-card is display: flex.
   This project has hit that trap three times (.nav-notif-badge, .gp-notice-dismissible, the
   Team Info tabs), so the rule is explicit here rather than left to the UA.
   -------------------------------------------------------------------------------------- */
.team-doc-panel[hidden] {
    display: none;
}

/* --------------------------------------------------------------------------------------
   The Tactics nav — a `.data-table` inside the left panel, because UI/Tables.md's D2 spine
   indicator (.expand-spine / .expand-notch / .expand-notch-glyph) is keyed on
   `tr[data-expandable]` for every hover and open state and therefore only works inside a
   table row. Roster/_RosterEventList.cshtml is the precedent for a table in a left panel.

   NOTHING ABOUT THE INDICATOR IS RESTATED HERE. The spine, the notch, the glyph, the hover
   and the expanded states are all site.css's, and this file must not override them — that
   is the whole point of using the standard rather than drawing an arrow.
   -------------------------------------------------------------------------------------- */
.team-doc-nav-table {
    /* .data-table is width:100%, which is right, but the panel supplies its own frame — no
       card wrapper here, unlike a table standing in a page (UI/Tables.md's card rule is
       about tables on the page background, not one inside a panel that already has one). */
    border-top: 1px solid var(--line-soft);

    /* `.data-table` ships `margin-bottom: 1.5rem`, which is spacing for a table standing in a
       page. In a nav panel it is just a gap under the last row.

       SITE.CSS ALREADY HAS A RULE FOR EXACTLY THIS — `.gp-card-table .gp-split-left-body >
       .data-table { margin-bottom: 0 }` — and it does not reach here, because this panel is
       `.gp-split-left.gp-card` and that selector needs `.gp-card-table`. Worth knowing before
       anyone "simplifies" this away: the reason recorded there is not cosmetic. A margin under
       a table inside a scrolling split panel is counted in the body's scrollHeight but not in
       its layout height, so the panel reports content taller than its box and draws a
       scrollbar on content that fits. */
    margin-bottom: 0;
}

/* --------------------------------------------------------------------------------------
   HIGHLIGHTS FOLLOW UI/Layout.md's TWO-COLUMN STANDARD, NOT UI/Tables.md's ROW TREATMENT.

   This is a MENU that happens to be built from a table — the table form is there for the D2
   expand indicator (see above), not because these rows are data. So they hover and select
   like every other `.gp-split-left-row` in the portal, and share the pale-blue selection
   colour with the Loot Distribution boss column, the Roster/Manage list and `.gp-list-active`.

   The table's own row rules outrank the panel's in two places, so both are corrected here:

     RESTING  `.data-table tbody tr` (0,1,2) paints `var(--bg-2)`, while `.gp-split-left-row`
              (0,1,0) declares no background at all — so every nav row would sit on a table
              band instead of on the panel. (It showed first as the Tactics row being a
              different colour from the four document rows, back when those were <button>s.)
     SUBROW   `.detail-row .data-table tbody tr` (0,2,2) and its `:hover` (0,3,2) both
              outrank `.gp-split-left-row`'s (0,2,0), so the boss rows got no hover and no
              selected state whatsoever.

   Hover and select on the TACTICS row itself already resolve correctly — `.gp-split-left-row`
   carries two classes and beats both table rules — so nothing restates them for it.
   -------------------------------------------------------------------------------------- */

/* Resting only. Excluding the two interactive states leaves site.css's own (0,2,0) rules to
   own them, so hover and selection are still the shared ones rather than copies. */
.data-table.team-doc-nav-table tbody tr:not(.is-active):not(:hover) {
    background: transparent;
}

/* THESE TWO ARE COPIES OF site.css's `.gp-split-left-row:hover` AND `.gp-split-left-row.is-active`.
   They exist only to outrank the subrow-table rules above; there is no way to raise a shared
   rule's specificity from a page stylesheet, and matching the shape is what UI/Tables.md
   prescribes when a page rule has to beat one.

   >> KEEP THE VALUES IN STEP WITH site.css. UI/Layout.md states that #dce6ff (accent and
   >> wash) and #aac8ff (edges) are NOT INTERCHANGEABLE, and four surfaces share them. If that
   >> pair ever changes, it changes here too — or this menu becomes the outlier the corrected
   >> `.gp-split-left-row.is-active` was written to stop existing. */
.data-table.tactics-nav-encounters-table tbody tr.gp-split-left-row:hover {
    background: linear-gradient(to right, rgba(255, 255, 255, 0.04), transparent);
}

.data-table.tactics-nav-encounters-table tbody tr.gp-split-left-row.is-active {
    background: linear-gradient(to right, color-mix(in oklch, var(--char-color, #dce6ff) 10%, transparent), transparent);
    box-shadow:
        inset 0 1px 0 color-mix(in oklch, var(--char-color, #aac8ff) 22%, transparent),
        inset 0 -1px 0 color-mix(in oklch, var(--char-color, #aac8ff) 22%, transparent),
        inset 2px 0 0 var(--char-color, #dce6ff);
}

/* The nav's own type size. A <td> inherits `.data-table`'s 0.813rem, which is the size a data
   table wants and not the size a left panel uses — 0.781rem is the established panel value,
   taken from `.loot-boss-row` and `.roster-list-date`, the two reference implementations
   UI/Layout.md names. It was set on `.team-doc-row` while the four documents were <button>s
   (which inherit no page font at all); moving them into the table moved the rule here, where
   it now covers all five rows at once instead of one kind of row.

   THE CHILD COMBINATORS ARE LOAD-BEARING. A descendant `.team-doc-nav-table td` would also
   match the INNER table's cells inside the subrow, overriding the 0.75rem that
   `.detail-row .data-table` gives them — the subrow would come out the same size as the nav
   above it and stop reading as nested. */
.team-doc-nav-table > tbody > tr > td {
    font-size: 0.781rem;
}

/* --------------------------------------------------------------------------------------
   The subrow holding the boss list.

   THE PANEL'S OWN PADDING IS REMOVED SO THE INNER TABLE SITS TIGHT TO THE EDGES, which is
   what Home/Dashboard.cshtml's Raid Roster card does (inline `style="padding:0"`) and is the
   look this copies.

   THE GRID FLOOR IS THE PART THAT BROKE THE LAYOUT. `.detail-panel` is
   `display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr))`, and that
   12rem MINIMUM cannot fit a 13rem `.gp-split-left` once the panel's 1.25rem padding and the
   spine's 1.375rem inset are added — the panel overflowed and the column grew a horizontal
   scrollbar. One track with no floor fixes it without abandoning the panel type.

   SPECIFICITY IS DELIBERATE, NOT DEFENSIVE. `.detail-panel.expand-spine-detail` is (0,2,0),
   so a (0,2,0) page rule would depend on source order; chaining the ancestor makes this
   (0,3,0) and unambiguous. Same shape Tables.md prescribes for beating
   `.gp-card-table .detail-row .detail-panel { gap: 0 }`.
   -------------------------------------------------------------------------------------- */
.team-doc-nav-table .detail-panel.expand-spine-detail {
    padding: 0;
    grid-template-columns: 1fr;
    gap: 0;
}

/* The inner table fills the panel. Its first cell already gets `padding-left: 1.5rem` from
   site.css's `.detail-row .data-table tr td:first-child:not(.col-expand)`, which is what
   clears the spine — do not add an inset here or the two stack. */
.tactics-nav-encounters-table {
    width: 100%;
    margin-bottom: 0;
}

/* THE NAME CELL MUST BE ALLOWED TO SHRINK, and this is what was still overflowing after the
   panel was fixed. The global `.col-name` is `max-width: 30ch`, which at this type size is
   wider than the whole 13rem `.gp-split-left` — so the cell claimed more than the column had
   and the controls were pushed out of view.

   `max-width: 0` is the auto-table-layout idiom for "take the space that is left, and
   ellipsis the rest". It does not mean zero width: in an auto layout the browser distributes
   remaining space to the cell regardless, and the declaration only removes the cell's claim
   on a larger intrinsic width. `.col-controls` keeps its `width: 1px` shrink-wrap from
   UI/Tables.md, so the controls take exactly what they need and the name takes the rest.

   The button inside carries its own overflow/ellipsis: constraining the cell alone would let
   a nowrap child overflow it. */
.tactics-nav-encounters-table .col-name {
    max-width: 0;
    overflow: hidden;
}

/* The name is a <button> so it is reachable by KEYBOARD and announced as a control — the row
   itself handles the mouse, and a <tr> is not focusable. It is not an <a>: there is no URL
   behind it, the panel swap is the whole navigation.

   It stretches the full cell so the text sits where the eye expects, but the click target is
   the ROW: at 0.75rem a boss name is a small target and a near-miss used to land on dead
   space, which is what this width alone did not solve. */
.tactics-nav-name {
    display: block;
    width: 100%;
    padding: 0;
    background: none;
    border: none;
    text-align: left;
    color: inherit;
    cursor: pointer;
    font: inherit;
    /* One line per boss. .col-name's own ellipsis is on the CELL; the button inside it needs
       its own, or a long name pushes the cell wide and the controls off the panel. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tactics-nav-name:hover {
    color: var(--accent-2);
}

/* A boss with no article yet. `.gp-split-left-row` gives every menu row `cursor: pointer`,
   which on these rows would promise something the click does not do — there is nothing to
   open until the + is used. The name is a <span> rather than a <button> for the same reason. */
.tactics-nav-encounters-table tbody tr.is-dimmed,
.tactics-nav-encounters-table tbody tr.is-dimmed .tactics-nav-name {
    cursor: default;
}

.tactics-nav-empty {
    padding: 0.5rem 0.5rem 0.5rem 1.5rem;
    margin: 0;
    color: var(--ink-3);
    font-size: 0.75rem;
}

/* --------------------------------------------------------------------------------------
   Icons for the add / publish / delete controls.

   PAGE-SCOPED CLASSES OVER SHARED SVGs. .roster-publish-icon and .roster-trash-icon are the
   roster page's own, and UI/ClassNaming.md is explicit that a component-scoped class used by
   a second unrelated page has the wrong name. archives.css already met this and answered it
   this way — a new class over the SAME file, so there is one glyph in the portal and no
   shared name that lies about who owns it.

   .te-add-icon is reused as-is rather than copied: it is already used by three views across
   two modules, which makes it established as shared rather than owned by one page.
   -------------------------------------------------------------------------------------- */
.tactics-publish-icon {
    display: inline-block;
    width: 0.875rem;
    height: 0.875rem;
    background-color: currentColor;
    mask: url('/img/publish.svg') no-repeat center / contain;
    -webkit-mask: url('/img/publish.svg') no-repeat center / contain;
}

/* Published reads at a glance, the same way the roster list marks a published roster. */
.tactics-publish-btn[data-published="1"] .tactics-publish-icon {
    background-color: var(--ok);
}

.tactics-trash-icon {
    display: inline-block;
    width: 0.875rem;
    height: 0.875rem;
    background-color: currentColor;
    mask: url('/img/trash.svg') no-repeat center / contain;
    -webkit-mask: url('/img/trash.svg') no-repeat center / contain;
}

/* Occupies the publish control's slot on an article that cannot be published yet, so the
   controls stay aligned down the column and the absence is explained rather than silent.

   warning.svg and var(--warn), which is `.roster-empty-icon` exactly — the roster list marks
   an empty ROSTER for the same reason and in the same place, and the two states are the same
   shape: the row is legitimate, but it cannot be published and nothing else on the site says
   so. It was note.svg until 2026-08-17; a note reads as information, and this is a caution.

   var(--warn), never var(--bad): the article is not broken, it is unfinished. */
/* IT OCCUPIES A CONTROL'S SLOT, NOT AN ICON'S. It stands in for the publish button, so its
   BOX is `.btn-icon`'s 1.375rem while its GLYPH stays the 0.875rem every other icon draws at.

   At 0.875rem square it was a smaller flex item than the buttons beside it, and the row came
   out misaligned twice over: the glyph sat off the button column, and — because
   `.col-controls` shrink-wraps to the WIDEST row's content — every row with a button pair
   sized the column, leaving this shorter content right-aligned inside it with a gap on the
   left that no other row had.

   The size goes on `mask-size` AFTER the shorthand, which resets it. Sizing the ELEMENT
   instead would scale the glyph with `contain` and make the warning larger than the trash. */
.tactics-empty-icon {
    display: inline-block;
    width: 1.375rem;
    height: 1.375rem;
    background-color: var(--warn);
    mask: url('/img/warning.svg') no-repeat center;
    -webkit-mask: url('/img/warning.svg') no-repeat center;
    mask-size: 0.875rem 0.875rem;
    -webkit-mask-size: 0.875rem 0.875rem;
}

/* --------------------------------------------------------------------------------------
   The image strip on the article panel.
   -------------------------------------------------------------------------------------- */
.tactics-image-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.5rem;
}

/* Each thumbnail is a copy control with its delete control pinned to the corner. The wrapper is
   `position: relative` so the delete button can sit over the image without reserving layout. */
.tactics-image {
    position: relative;
    width: 6rem;
    height: 6rem;
}

.tactics-image-copy {
    display: block;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0.0625rem solid var(--line);
    border-radius: var(--r-sm);
    background: none;
    cursor: pointer;
    overflow: hidden;
}

.tactics-image-copy:hover {
    border-color: var(--accent);
}

/* Confirms the copy without a notice. UI/RichTextEditor.md's "no success message" rule is about
   saves, but the reasoning carries: the feedback belongs on the control that was pressed. */
.tactics-image-copy.is-copied {
    border-color: var(--ok);
}

.tactics-image-copy img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.tactics-image .js-tactics-image-delete {
    position: absolute;
    top: 0.125rem;
    right: 0.125rem;
}

/* --------------------------------------------------------------------------------------
   The upload dropzone. Drag-and-drop only — Systems/FileUpload.md forbids <input type="file">,
   so this element IS the control and has to read as one.
   -------------------------------------------------------------------------------------- */
.tactics-dropzone {
    margin-top: 0.5rem;
    padding: 1rem;
    border: 0.0625rem dashed var(--line);
    border-radius: var(--r-sm);
    text-align: center;
    font-size: 0.813rem;
    color: var(--ink-3);
}

.tactics-dropzone.is-over {
    border-color: var(--accent);
    color: var(--ink);
}

/* =====================================================================
   THE READER'S SIDE — the Team Info tactics panel and the Journal tree.
   Added 2026-08-17.
   ===================================================================== */

.tactics-reader-card {
    margin-bottom: 0;
}

/* Space between the panel's content and the card's bottom border.

   1.125rem MATCHES `.gp-card-inset`'s LEFT AND RIGHT PADDING, which is the class this panel already
   carries — so the content sits the same distance from all three edges instead of landing on the
   bottom one.

   IT GOES HERE, NOT ON THE COMPONENT AND NOT ON .gp-card-inset. A `.gp-outline` must not reserve
   space beneath itself — what is under it is its container's business, and its last item is
   deliberately flush. `.gp-card-inset` is shared and carries the horizontal distance ONLY by
   design, on the reasoning that whatever sits in it brings its own bottom margin; the outline is
   the case where that does not hold.

   Both tabs get it, deliberately: rendered rich text on the Notes tab would sit just as tight. */
.tactics-reader-panel {
    padding-bottom: 1.125rem;
}

/* One tab panel visible at a time. [hidden] needs the explicit rule wherever an author `display`
   could beat the UA's — the trap this project has hit four times now.

   AFTER the rule above, so `display: none` is not competing with a padding declaration for the same
   element at the same specificity. */
.tactics-reader-panel[hidden] {
    display: none;
}

/* The Collapse all / Expand all row above the journal outline.

   RIGHT-ALIGNED, the portal's default for controls. Nothing overrides justify-content and neither
   button is pushed away with margin-left:auto - that drags the other one left (UI/Cards.md). */
.tactics-journal-controls {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

/* The journal's title line. `.gp-outline-head` already supplies the weight and colour; this stays
   as the hook the spell link and Wowhead's injected icon are scoped to, so neither rule reaches
   another `.gp-outline` elsewhere in the portal. */
.tactics-journal-title {
    font-weight: 600;
    color: var(--ink);
}

/* An ability title that links to Wowhead.

   IT MUST NOT LOOK LIKE A LINK AT REST. The whole column is section titles; colouring and
   underlining only the ability ones would read as a different KIND of row rather than as the same
   row with more information behind it. So it inherits the title's colour and weight and shows its
   affordance on hover only.

   The tooltip is Wowhead's own — nothing here styles it, and nothing here should try: it is
   injected at the end of <body> by their script and is outside this page's scope. */
.tactics-journal-spell-link {
    color: inherit;
    text-decoration: none;
}

.tactics-journal-spell-link:hover,
.tactics-journal-spell-link:focus-visible {
    color: var(--accent-2);
    text-decoration: underline;
}

/* Wowhead's iconizeLinks inserts its own icon element before the link text.

   THE SIZE IS WOWHEAD'S, NOT OURS. `whTooltips.iconSize` in Team.cshtml governs it; this rule
   supplies only the SPACING and the vertical alignment. An earlier version forced width and height
   here, which fought the setting that exists for exactly this and would have made changing the size
   a two-file edit.

   THE WHOLE CLASS FAMILY IS LISTED because the class Wowhead emits follows iconSize - `icontinyl`
   for tiny (the default), `iconsmall` for small, and so on. Naming only two of them is why the
   spacing did not apply at first: the icons were rendering as `icontinyl` and no rule reached them.
   Listing all of them means the spacing survives a change to the setting. */
.tactics-journal-title .icontinyl,
.tactics-journal-title .icontinyr,
.tactics-journal-title .icontiny,
.tactics-journal-title .iconsmall,
.tactics-journal-title .iconmedium,
.tactics-journal-title .iconlarge {
    margin-right: 0.5rem;

    /* CENTRED AGAINST THE TEXT, not nudged off the baseline. `middle` lines the icon's centre up
       with the text's own centre, so it stays right whatever the tier's font-size is - and this
       component has two of them (0.813rem at the top level, 0.75rem below). A fixed negative
       offset was correct at one size and slightly wrong at the other. */
    vertical-align: middle;
}

/* Room above and below a section's prose, inside an outline body.

   ON THE PROSE BLOCK, NOT ON .gp-outline-body's PADDING. The body's top padding is deliberately
   tight so a section whose first child is a nested LIST sits close to its own title; only the case
   where there is text to read wants more air.

   The bottom margin collapses with .tactics-journal-role-cards' own top margin rather than adding
   to it, so the Overview's description keeps one gap above its cards and not two. */
.gp-outline-body > .tactics-journal-body {
    margin-top: 0.375rem;
    margin-bottom: 0.625rem;
}

/* Prose inside an expanded section. The transform emits <p> and <ul>, nothing else. */
.tactics-journal-body p {
    margin: 0 0 0.5rem;
    line-height: 1.5;
}

.tactics-journal-body p:last-child {
    margin-bottom: 0;
}

.tactics-journal-list {
    margin: 0 0 0.5rem;
    padding-left: 1.125rem;
}

/* Role-card bullets breathe more than the tree's do.

   SCOPED TO THE ROLE CARDS, not to every journal list. In the tree a section's bullets are one
   block of prose among nested boxes and the tighter global rhythm is right there; in a card they
   are the ENTIRE content, three or four short instructions read at a glance, and 0.4rem runs them
   together.

   0.4rem is site.css's global `ol li, ul li` value, which is what this raises. Everything else in
   the journal keeps it. */
.tactics-journal-role-card .tactics-journal-list li {
    margin-bottom: 0.625rem;
}

/* The card body's padding supplies the space under the last bullet; the margin would double it. */
.tactics-journal-role-card .tactics-journal-list li:last-child {
    margin-bottom: 0;
}

/* An inline [Ability] reference. The game colours these; this marks them the same way so a reader
   can see at a glance that a name refers to a mechanic described elsewhere in the tree.

   NOT a link — the journal response gives a spell id but no target, and turning it into an
   outbound link was declined 2026-08-17. */
.tactics-journal-ability {
    color: var(--accent-2);
    font-weight: 600;
}

/* ---------------------------------------------------------------------
   Overview's role cards.

   THE GRID IS THIS WRAPPER'S OWN. It used to be inherited from `.detail-panel`
   (`repeat(auto-fit, minmax(12rem, 1fr))`) and overridden in place, because the cards sat directly
   in the expanded panel of a D2 row. `.gp-outline-body` is a plain block with no grid of its own,
   so the cards bring one.

   EACH CARD TAKES AN EQUAL SHARE — three roles, three thirds. auto-fit sized to the CONTAINER and
   left a quarter of a wide panel empty; this sizes to the CONTENT. The count comes from the view as
   `--tactics-role-columns`, so a boss with only two role sections gets halves.
   --------------------------------------------------------------------- */
.tactics-journal-role-cards {
    display: grid;
    grid-template-columns: repeat(var(--tactics-role-columns, 3), 1fr);
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

/* Space between the Overview's description and the cards under it.

   ADJACENT SIBLING, NOT A PLAIN margin-top, so the gap exists only when there IS a description
   above. The body div is not rendered at all when the section carries no prose, and an
   unconditional top margin would then push the cards down from nothing.

   0.75rem is the grid's own gap, so the space above the first row matches the space between the
   cards and the whole block reads as one rhythm rather than three values.

   It is needed because `.tactics-journal-body p:last-child` zeroes the final paragraph's bottom
   margin — correct inside a card body, where the padding supplies the space, but it leaves the
   prose sitting flush against whatever follows it here. */
.tactics-journal-body + .tactics-journal-role-cards {
    margin-top: 0.75rem;
}

@media (max-width: 48em) {
    .tactics-journal-role-cards {
        grid-template-columns: 1fr;
    }
}

/* The header strip gains an icon, so it becomes a row. `.gp-section-card-header` supplies the
   background, the uppercase type and the padding; only the layout is added here. */
.tactics-journal-role-card .gp-section-card-header {
    display: flex;
    align-items: center;
    gap: 0.375rem;
}

/* .role-icon is 1.375rem — taller than the strip's own line box, so the strip grows to fit it.
   That is intended: the icon is what makes a role card identifiable at a glance, which is the
   whole reason these three are cards rather than rows. */
/* SMALLER THAN THE SITE-WIDE .role-icon (1.375rem / 0.875rem glyph), and only here.

   In a card header the icon is a LABEL for three words, not a control being scanned for in a
   roster row - at full size it outweighs the text beside it and the strip grows to fit it. The
   base class is untouched: every other surface that draws a role icon keeps the standard size. */
.tactics-journal-role-card .role-icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
}

.tactics-journal-role-card .role-icon-svg {
    width: 0.75rem;
    height: 0.75rem;
}
