/*
 * ET-Docs design system v0.2 - "instrument-grade".
 *
 * Calm, scientific, precise. Type carries the weight; colour is
 * codified (each pipeline P1-P7 has its own true hue). One signature
 * graphical move: the hero ripple (drawn from scripts/et-docs-ripple.js).
 *
 * Coexists with w3.css during the incremental refresh. All selectors
 * carry an `etd-` prefix so they never clash with `w3-*` rules.
 *
 * Direction reference: docs/et-docs-ui-direction.md (v0.1 doc;
 * v0.2 mock published 2026-06-30).
 */

/* ============================================================
   Tokens
   ============================================================ */
:root {
    /* Neutrals - cool, measured blue bias */
    --etd-bg:          #F4F6FA;
    --etd-bg-alt:      #FBFCFE;
    --etd-surface:     #FFFFFF;
    --etd-ink:         #0A1525;
    --etd-ink-quiet:   #5A6477;
    --etd-ink-faint:   #97A0B0;
    --etd-rule:        #E0E5EF;
    --etd-rule-strong: #C5CCDB;

    /* Primary */
    --etd-primary:        #1E3FAA;
    --etd-primary-hover:  #152F84;
    --etd-primary-soft:   #E6ECF9;
    --etd-primary-ink:    #0A1F5C;

    /* Accent - used only on action CTAs */
    --etd-accent:        #D08C25;
    --etd-accent-hover:  #A86E15;
    --etd-accent-soft:   #FAEDD3;

    /* Semantic state - separate from accent */
    --etd-good:        #2A8C5A;
    --etd-good-soft:   #E1F0E9;
    --etd-warn:        #C68B1B;
    --etd-warn-soft:   #F8EDD0;
    --etd-crit:        #C13F3D;
    --etd-crit-soft:   #FAE3E2;

    /* Pipeline hues - codified, not tints */
    --etd-p1:  #1E3FAA;
    --etd-p2:  #4A6BB5;
    --etd-p3:  #2A8C5A;
    --etd-p4:  #7639AD;
    --etd-p5:  #B5631F;
    --etd-p5b: #B58F3F;
    --etd-p6:  #C8413F;
    --etd-p7:  #5A6477;

    /* Type */
    /* Font stack unified with etmd-next / tailwind.src.css so both
       apps read as siblings and the whole ET-Docs surface uses one
       family (Inter) whether it's on the Tailwind chrome or one of
       the still-legacy pages.  Historical "Iowan Old Style" serif
       for display headings retired at the same time - etmd-next
       uses Inter for both display and body.  Inter is loaded via
       Google Fonts from the page templates. */
    --etd-serif: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --etd-sans:  "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --etd-mono:  ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, "Liberation Mono", monospace;

    --etd-radius:    6px;
    --etd-radius-sm: 4px;
    --etd-radius-lg: 10px;

    --etd-shadow-1: 0 1px 0 rgba(10, 21, 37, .03), 0 1px 3px rgba(10, 21, 37, .03);
    --etd-shadow-2: 0 2px 8px rgba(10, 21, 37, .06);
    --etd-shadow-cta: 0 1px 0 rgba(168, 110, 21, .25), 0 2px 6px rgba(208, 140, 37, .25);
}

/* ============================================================
   Reset for the new top bar (applies at <body> level because the
   top bar is part of every page chrome). The reset is light:
   only what's needed to make our typography land cleanly without
   stomping on legacy w3.css pages.
   ============================================================ */
body.etd-shell { margin: 0; background: var(--etd-bg); color: var(--etd-ink); }
body.etd-shell { font-family: var(--etd-sans); }

/* Beat w3.css's bare `h1,h2,h3,h4,h5,h6 { font-family: "Segoe UI" }`
   rule (specificity 0,0,0,1) that would otherwise win over the
   Inter inherited from body on every heading emitted by the new
   Tailwind chrome (dashboard, codifier list, reviews, etc.).
   Specificity here is (0,0,1,2) - body.etd-shell h1 - which beats
   the w3.css rule cleanly without needing !important.  Applied
   across every text-carrying element for the same reason (w3.css
   also declares Verdana on html,body which is beaten by
   body.etd-shell above, but any child element that inherits
   font-family from html rather than body would leak Verdana). */
body.etd-shell h1, body.etd-shell h2, body.etd-shell h3,
body.etd-shell h4, body.etd-shell h5, body.etd-shell h6 {
    font-family: var(--etd-sans);
}

/* Tailwind display-utility overrides.
 *
 * Tailwind's display utilities (.hidden, .block, .flex, .inline,
 * responsive .md:hidden, .md:flex, .sm:inline, etc.) live inside
 * @layer utilities.  On ET-Docs authenticated pages we ALSO load
 * a full legacy CSS stack (docs.css, w3.css, jquery-ui.css,
 * font-awesome, and this file), all un-layered - and un-layered
 * author regular declarations have HIGHER cascade priority than
 * layered author regular declarations per CSS Cascade Layer
 * spec.  So Tailwind's regular .hidden was being beaten by some
 * unlayered legacy rule, leaving the mobile-nav panel visible on
 * wide viewports and the desktop-only nav visible on small ones
 * (the two "displays twice" reports).
 *
 * Fix: promote every display utility we actually use in the
 * chrome markup (build_nav_bars + templates/_layout.php + the
 * dashboard hero) to un-layered !important.  Layered !important
 * would also work but requires touching the tailwind.src.css
 * layer setup; a plain un-layered !important override is
 * simpler and only affects the exact utility class names listed.
 *
 * Not needed for etmd-next because it loads only
 * tailwind.build.css - no legacy stack to fight with. */
.hidden      { display: none        !important; }
.block       { display: block       !important; }
.flex        { display: flex        !important; }
.inline      { display: inline      !important; }
.inline-flex { display: inline-flex !important; }
.grid        { display: grid        !important; }
@media (min-width: 40rem) {
    .sm\:inline { display: inline !important; }
    .sm\:hidden { display: none   !important; }
    .sm\:flex   { display: flex   !important; }
    .sm\:block  { display: block  !important; }
}
@media (min-width: 48rem) {
    .md\:flex        { display: flex        !important; }
    .md\:hidden      { display: none        !important; }
    .md\:inline      { display: inline      !important; }
    .md\:inline-flex { display: inline-flex !important; }
    .md\:block       { display: block       !important; }
}
@media (min-width: 64rem) {
    .lg\:grid   { display: grid   !important; }
    .lg\:flex   { display: flex   !important; }
    .lg\:hidden { display: none   !important; }
    .lg\:block  { display: block  !important; }
}

/* Breathing room between the top-of-page <header> nav and the
   interior content that follows it.  Etmd-next wraps interior
   content in <main class="max-w-7xl mx-auto px-4 md:px-6 py-8">.
   ET-Docs's authenticated pages emit content as a direct sibling
   of <header>; this selector adds the equivalent top padding to
   whichever element renders next, without needing per-page
   markup changes.  The nav's inline <script> was moved INSIDE
   <header> so the "first sibling after header" is guaranteed
   to be the page content (previously the script became the
   first sibling and swallowed the padding).  Sibling selector
   `header +` also ensures modals + drawers appended later in
   the DOM don't get double-spacing. */
body.etd-shell > header + * {
    padding-top: 2rem;
}

/* Un-layered color-utility overrides to beat w3.css's un-layered
   `a { color: inherit }` (line 37).  Tailwind's `.text-accent-*`
   and `.text-n-*` classes live in @layer utilities, which loses
   to un-layered author rules per CSS Cascade Layer spec.  So on
   authenticated pages the active-nav highlight's text-accent-700
   (and every other anchor-coloured accent utility) was getting
   overridden to inherit the parent's grey.  Un-layered here means
   these beat w3.css's `a` rule cleanly on specificity, no
   !important needed. */
.text-accent-500 { color: var(--color-accent-500); }
.text-accent-600 { color: var(--color-accent-600); }
.text-accent-700 { color: var(--color-accent-700); }
.text-coral-600  { color: var(--color-coral-600);  }
.text-coral-700  { color: var(--color-coral-700);  }
.text-n-300 { color: var(--color-n-300); }
.text-n-400 { color: var(--color-n-400); }
.text-n-500 { color: var(--color-n-500); }
.text-n-600 { color: var(--color-n-600); }
.text-n-700 { color: var(--color-n-700); }
.text-n-800 { color: var(--color-n-800); }
.text-white { color: #ffffff; }

/* Hover variants of the above - same rationale.  The class
   selectors have a hover pseudo-class which lifts specificity
   above the un-layered `a` rule regardless of layer. */
.hover\:text-accent-600:hover { color: var(--color-accent-600); }
.hover\:text-accent-700:hover { color: var(--color-accent-700); }
.hover\:text-coral-700:hover  { color: var(--color-coral-700);  }
.hover\:text-n-600:hover { color: var(--color-n-600); }
.hover\:text-n-700:hover { color: var(--color-n-700); }
.hover\:text-n-800:hover { color: var(--color-n-800); }

/* Un-layered background-color overrides.  Same cascade fight as
   the color utilities above: w3.css has an un-layered
   `a { background-color: transparent }` (line 8) that beat
   Tailwind's layered .bg-accent-* on anchors, so the active-nav
   highlight's bg-accent-50 never rendered.  Un-layered class
   selectors here beat w3.css's element selector on specificity. */
.bg-accent-50  { background-color: var(--color-accent-50);  }
.bg-accent-100 { background-color: var(--color-accent-100); }
.bg-accent-500 { background-color: var(--color-accent-500); }
.bg-coral-50   { background-color: var(--color-coral-50);   }
.bg-n-0   { background-color: var(--color-n-0);   }
.bg-n-50  { background-color: var(--color-n-50);  }
.bg-n-100 { background-color: var(--color-n-100); }
.bg-n-200 { background-color: var(--color-n-200); }
.bg-n-800 { background-color: var(--color-n-800); }
.bg-transparent { background-color: transparent; }

/* Hover variants of bg-* utilities. */
.hover\:bg-accent-50:hover  { background-color: var(--color-accent-50);  }
.hover\:bg-accent-600:hover { background-color: var(--color-accent-600); }
.hover\:bg-coral-50:hover   { background-color: var(--color-coral-50);   }
.hover\:bg-n-50:hover  { background-color: var(--color-n-50);  }
.hover\:bg-n-100:hover { background-color: var(--color-n-100); }
.hover\:bg-n-900:hover { background-color: var(--color-n-900); }

/* Border-color overrides for the active-nav pill (border border-accent-100)
   and various card / panel borders. */
.border-accent-100 { border-color: var(--color-accent-100); }
.border-accent-200 { border-color: var(--color-accent-200); }
.border-n-100 { border-color: var(--color-n-100); }
.border-n-200 { border-color: var(--color-n-200); }
.border-n-300 { border-color: var(--color-n-300); }

/* Font-size normalisation.  w3.css sets html + body to 15px
   (line 30); etmd-next uses browser default 16px.  ET-Docs was
   rendering everything 6.7% smaller as a result.  Reset html
   to 16px so rem-based sizing matches etmd-next, then let
   body inherit.  Legacy content that uses absolute px sizing
   is unaffected; only rem/em values (Tailwind's text-* etc.)
   scale up to match etmd-next's rendering. */
html      { font-size: 16px; }
body      { font-size: 1rem; }

/* Button-primary + button-secondary text-colour override.
 * When these Tailwind component classes are rendered on an <a>
 * (Edit metadata, + New document, Sign out of IAM, etc.),
 * w3.css's un-layered `a { color: inherit }` beats the layered
 * .btn-primary { color: white } rule, so the button label was
 * rendering in the parent's colour (grey / dark) against a blue
 * gradient - unreadable.  Un-layered override here restores
 * white text via specificity.  Applies to hover/focus states
 * too so the label doesn't flicker on interaction. */
.btn-primary,
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary:visited,
.btn-secondary,
.btn-secondary:hover,
.btn-secondary:focus,
.btn-secondary:active,
.btn-secondary:visited { color: #ffffff; text-decoration: none; }

/* Scope wrapper for new-style pages */
.etd-scope { color: var(--etd-ink); font: 15px/1.55 var(--etd-sans); -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
.etd-scope * { box-sizing: border-box; }

.etd-scope h1, .etd-scope h2, .etd-scope h3, .etd-scope h4 {
    font-family: var(--etd-serif); font-weight: 600;
    color: var(--etd-ink); margin: 0; text-wrap: balance;
    letter-spacing: -0.012em;
}
.etd-scope .etd-display { font-family: var(--etd-serif); font-size: clamp(40px, 5vw, 56px); line-height: 1.05; letter-spacing: -0.025em; font-weight: 600; }
.etd-scope h1 { font-size: 32px; line-height: 1.15; }
.etd-scope h2 { font-size: 22px; line-height: 1.25; letter-spacing: -0.008em; }
.etd-scope h3 { font-size: 17px; line-height: 1.3; letter-spacing: 0; }
.etd-scope p  { margin: 0; }
.etd-scope a       { color: var(--etd-primary); text-decoration: none; }
.etd-scope a:hover { text-decoration: underline; text-underline-offset: 2px; }
.etd-scope :focus-visible { outline: 2px solid var(--etd-primary); outline-offset: 2px; border-radius: var(--etd-radius-sm); }

/* Utility text */
.etd-lede     { font-size: 17px; color: var(--etd-ink-quiet); max-width: 60ch; line-height: 1.55; }
.etd-meta     { font-size: 13px; color: var(--etd-ink-quiet); }
.etd-label-up { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--etd-ink-quiet); }
.etd-num      { font-variant-numeric: tabular-nums; }

/* Doc-code chrome */
.etd-doc-code {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 8px;
    background: var(--etd-bg);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-sm);
    font: 12.5px/1 var(--etd-mono);
    color: var(--etd-primary-ink);
    font-variant-numeric: tabular-nums;
}
.etd-doc-code-lg {
    padding: 4px 12px; font-size: 16px;
    background: var(--etd-primary-soft);
    border-color: #C7D5F4;
}

/* ============================================================
   Top bar - light, editorial. Serif wordmark anchors the brand.
   Coexists with legacy body content below it.
   ============================================================ */
.etd-topbar {
    background: var(--etd-surface);
    border-bottom: 1px solid var(--etd-rule);
    padding: 0 28px;
    height: 60px;
    display: flex;
    align-items: center;
    gap: 32px;
    position: sticky; top: 0; z-index: 50;
    font-family: var(--etd-sans);
}
.etd-wordmark {
    display: inline-flex; align-items: center; gap: 8px;
    font-family: var(--etd-serif); font-size: 22px; font-weight: 700;
    color: var(--etd-ink); letter-spacing: -0.02em;
    text-decoration: none;
}
.etd-wordmark:hover { text-decoration: none; }
.etd-wordmark .etd-glyph {
    display: inline-block; width: 22px; height: 22px;
    background: url("../resources/et-docs-icon.svg") center/contain no-repeat;
    flex-shrink: 0;
}
.etd-nav { display: flex; gap: 2px; }
.etd-nav a {
    display: inline-flex; align-items: center;
    padding: 7px 12px; border-radius: var(--etd-radius-sm);
    color: var(--etd-ink-quiet); font-size: 14px;
    text-decoration: none; font-weight: 500;
    line-height: 1.4;
}
.etd-nav a:hover { background: var(--etd-bg); color: var(--etd-ink); text-decoration: none; }
.etd-nav a[aria-current="page"] { color: var(--etd-ink); background: var(--etd-bg); }

.etd-topbar-right { margin-left: auto; display: flex; align-items: center; gap: 14px; }
.etd-search-bar {
    background: var(--etd-bg);
    border: 1px solid transparent;
    border-radius: var(--etd-radius);
    padding: 7px 12px 7px 32px;
    font: 13.5px/1.4 var(--etd-sans);
    color: var(--etd-ink);
    width: 320px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235A6477' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: 12px 50%;
}
.etd-search-bar:focus { background-color: var(--etd-surface); border-color: var(--etd-rule-strong); outline: 0; box-shadow: 0 0 0 3px var(--etd-primary-soft); }
.etd-kbd {
    border: 1px solid var(--etd-rule); border-bottom-width: 2px;
    border-radius: 3px; padding: 1px 5px;
    font: 11px/1 var(--etd-mono); color: var(--etd-ink-quiet);
    background: var(--etd-bg-alt);
}
.etd-avatar {
    width: 32px; height: 32px; border-radius: 50%;
    background: var(--etd-primary); color: white;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 600;
    text-decoration: none;
    user-select: none;
    cursor: pointer;
}
.etd-avatar:hover { text-decoration: none; }

/* User menu - details/summary native disclosure pattern, no JS */
.etd-user-menu { position: relative; }
.etd-user-menu summary { list-style: none; }
.etd-user-menu summary::-webkit-details-marker { display: none; }
.etd-user-menu summary::marker { display: none; }
.etd-user-menu[open] .etd-avatar {
    box-shadow: 0 0 0 3px var(--etd-primary-soft);
}
.etd-user-dropdown {
    position: absolute; right: 0; top: calc(100% + 8px);
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    box-shadow: 0 8px 24px rgba(10, 21, 37, .12);
    min-width: 240px;
    padding: 6px;
    z-index: 200;
    animation: etd-dropdown-in .12s ease-out;
}
@keyframes etd-dropdown-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}
.etd-user-dropdown-head {
    padding: 10px 12px 12px;
    border-bottom: 1px solid var(--etd-rule);
    margin-bottom: 4px;
}
.etd-user-name  { font-weight: 600; font-size: 14px; color: var(--etd-ink); line-height: 1.35; }
.etd-user-id    { font-size: 12px; color: var(--etd-ink-quiet); margin-top: 2px; font-family: var(--etd-mono); }
.etd-user-dropdown-link {
    display: block;
    padding: 8px 12px;
    font-size: 14px; color: var(--etd-ink);
    border-radius: var(--etd-radius-sm);
    text-decoration: none;
}
.etd-user-dropdown-link:hover { background: var(--etd-bg); text-decoration: none; }
.etd-user-dropdown-divider { height: 1px; background: var(--etd-rule); margin: 4px -6px; }
.etd-user-dropdown-sign-out { color: var(--etd-crit); }
.etd-user-dropdown-sign-out:hover { background: var(--etd-crit-soft); }

/* Public-access badge for the topbar (when serving unauth) */
.etd-public-badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 9px; border-radius: 999px;
    background: var(--etd-good-soft); color: var(--etd-good);
    font-size: 11.5px; font-weight: 600; letter-spacing: 0.02em;
}

/* ============================================================
   Layout primitives
   ============================================================ */
.etd-container { max-width: 1240px; margin: 0 auto; padding: 40px 28px 60px; }
.etd-page      { max-width: 1240px; margin: 0 auto; padding: 32px 28px 64px; }
.etd-page-head { display: flex; flex-direction: column; gap: 8px; margin-bottom: 24px; }
.etd-eyebrow   { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.etd-stack     { display: flex; flex-direction: column; gap: 10px; }
.etd-stack-lg  { display: flex; flex-direction: column; gap: 16px; }
.etd-cluster   { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* ============================================================
   Hero - sits flush under topbar, ripple background canvas inside
   ============================================================ */
.etd-hero {
    position: relative; overflow: hidden;
    background: linear-gradient(180deg, var(--etd-surface), var(--etd-bg-alt));
    border-bottom: 1px solid var(--etd-rule);
}
.etd-hero-canvas {
    position: absolute; inset: 0; width: 100%; height: 100%;
    opacity: 0.55; pointer-events: none;
}
.etd-hero-inner {
    position: relative; max-width: 1240px; margin: 0 auto;
    padding: 64px 28px 56px;
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    gap: 40px; align-items: end;
}
@media (max-width: 900px) { .etd-hero-inner { grid-template-columns: 1fr; } }
.etd-hero-eyebrow {
    display: flex; align-items: center; gap: 10px;
    font-size: 12px; color: var(--etd-ink-quiet); letter-spacing: 0.04em;
    text-transform: uppercase; font-weight: 600;
    margin-bottom: 14px;
}
.etd-hero-eyebrow .etd-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--etd-good); }
.etd-hero-sub { font-size: 16px; color: var(--etd-ink-quiet); max-width: 56ch; line-height: 1.55; margin-top: 14px; }
.etd-hero-stat-strip { display: flex; gap: 40px; margin-top: 28px; padding-top: 20px; border-top: 1px solid var(--etd-rule); flex-wrap: wrap; }
.etd-stat { display: flex; flex-direction: column; }
.etd-stat .etd-num-big { font-family: var(--etd-serif); font-size: 30px; font-weight: 600; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; line-height: 1; }
.etd-stat .etd-lbl { font-size: 12px; color: var(--etd-ink-quiet); margin-top: 6px; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }

/* ============================================================
   Buttons / CTAs
   ============================================================ */
/* Primary CTA - ET brand blue with white text. Contrast ~9:1
   (AAA) - reads confidently at every screen brightness. Amber
   was tried first but sat in a mid-brightness zone where
   neither white nor dark ink gave AAA contrast, and both
   looked washed out. Amber is now reserved for smaller accent
   roles (chips, tags, active-tab underline, "LATEST" pill).

   Selector prefixed with `.etd-scope` so the class beats the
   `.etd-scope a` default-anchor rule (0,1,1) - without the
   prefix, `.etd-cta` at 0,1,0 loses to the anchor rule and the
   button label renders primary-blue on primary-blue (invisible). */
.etd-scope .etd-cta {
    align-self: end;
    display: inline-flex; align-items: center; gap: 8px;
    background: var(--etd-primary); color: white;
    padding: 12px 20px; border-radius: var(--etd-radius);
    font: 600 14px/1 var(--etd-sans);
    border: none; cursor: pointer;
    box-shadow: var(--etd-shadow-cta);
    transition: background .12s, transform .12s;
    text-decoration: none;
}
.etd-scope .etd-cta:hover { background: var(--etd-primary-hover); color: white; text-decoration: none; }
.etd-scope .etd-cta .etd-cta-arrow { transition: transform .15s; }
.etd-scope .etd-cta:hover .etd-cta-arrow { transform: translateX(2px); }
.etd-scope .etd-cta-ghost {
    background: transparent; color: var(--etd-ink-quiet);
    border: 1px solid var(--etd-rule-strong);
    padding: 10px 16px; border-radius: var(--etd-radius);
    font: 500 14px/1 var(--etd-sans); cursor: pointer;
    display: inline-flex; align-items: center; gap: 6px;
    transition: border-color .12s, color .12s;
    text-decoration: none;
}
.etd-scope .etd-cta-ghost:hover { border-color: var(--etd-ink-faint); color: var(--etd-ink); text-decoration: none; }

/* Legacy alias kept for the triage form (etd-button-* - still works) */
.etd-button { appearance: none; border: 1px solid transparent; padding: 10px 18px; font: 600 14px/1 var(--etd-sans); border-radius: var(--etd-radius); cursor: pointer; transition: background .12s, border-color .12s, color .12s; text-decoration: none; display: inline-flex; align-items: center; gap: 8px; }
/* Button variants - all prefixed with .etd-scope so the class-
   colour rules beat the .etd-scope a default-anchor blue when the
   button is rendered as an <a>. Without the prefix, anchor-based
   buttons render the label text in the primary-blue anchor
   colour, matching their own background and going invisible. */
.etd-scope .etd-button-primary { background: var(--etd-primary); color: white; }
.etd-scope .etd-button-primary:hover { background: var(--etd-primary-hover); color: white; text-decoration: none; }
/* .etd-button-accent: retained as an alias for etd-button-primary
   so callers don't need renaming. Amber-background + white-text
   sat at ~2.1:1 (fails AA); primary-blue + white gives ~9:1
   (AAA). Any place a "warm" button was intended can migrate to
   the (ghost / outlined) variants - amber is now reserved for
   smaller accent roles. */
.etd-scope .etd-button-accent  { background: var(--etd-primary); color: white; }
.etd-scope .etd-button-accent:hover { background: var(--etd-primary-hover); color: white; text-decoration: none; }
.etd-scope .etd-button-ghost   { background: transparent; color: var(--etd-ink-quiet); border-color: var(--etd-rule-strong); }
.etd-scope .etd-button-ghost:hover { color: var(--etd-ink); border-color: var(--etd-ink-faint); text-decoration: none; }
/* Unscoped fall-throughs so callers outside .etd-scope (the review-
   detail Comments panel, the Codifier metadata form, the review-
   triage disclaimer modal, the Files upload button, ...) still get
   the primary + ghost button chrome.  Colour is set explicitly so
   an <a>-as-button doesn't render its label in the default anchor
   blue against the primary-blue background - the concern the
   original `.etd-scope` prefix was guarding against. */
.etd-button-accent  { background: var(--etd-primary); color: white; border-color: var(--etd-primary); }
.etd-button-accent:hover { background: var(--etd-primary-hover); color: white; border-color: var(--etd-primary-hover); text-decoration: none; }
.etd-button-accent:focus-visible { outline: 2px solid var(--etd-primary); outline-offset: 2px; }
.etd-button-ghost   { background: transparent; color: var(--etd-ink-quiet); border-color: var(--etd-rule-strong); }
.etd-button-ghost:hover { background: var(--etd-surface); color: var(--etd-ink); border-color: var(--etd-ink-faint); text-decoration: none; }
.etd-button-ghost:focus-visible { outline: 2px solid var(--etd-primary); outline-offset: 2px; }

/* Native <input type="file"> Browse-button styling.  The browser's
   default "Choose File" pill reads as system chrome and doesn't
   match the app's own buttons; ::file-selector-button (with the
   -webkit- vendor prefix as a fallback for Safari <15) lets us
   restyle it in-place without swapping the input for a custom
   label + hidden input.  Apply to any file input that opts in via
   the .etd-file-input class. */
.etd-file-input {
    font: 400 13px/1.3 var(--etd-sans);
    color: var(--etd-ink);
    max-width: 100%;
}
.etd-file-input::file-selector-button {
    appearance: none;
    padding: 8px 14px;
    margin-right: 10px;
    background: var(--etd-primary);
    color: white;
    border: 1px solid var(--etd-primary);
    border-radius: var(--etd-radius);
    font: 600 13px/1 var(--etd-sans);
    cursor: pointer;
    transition: background .12s, border-color .12s;
}
.etd-file-input::file-selector-button:hover {
    background: var(--etd-primary-hover);
    border-color: var(--etd-primary-hover);
}
.etd-file-input::-webkit-file-upload-button {
    appearance: none;
    padding: 8px 14px;
    margin-right: 10px;
    background: var(--etd-primary);
    color: white;
    border: 1px solid var(--etd-primary);
    border-radius: var(--etd-radius);
    font: 600 13px/1 var(--etd-sans);
    cursor: pointer;
}
.etd-file-input::-webkit-file-upload-button:hover {
    background: var(--etd-primary-hover);
    border-color: var(--etd-primary-hover);
}

/* ============================================================
   Quick-action cards (homepage)
   ============================================================ */
.etd-actions-row {
    display: grid; grid-template-columns: repeat(4, 1fr);
    gap: 14px; margin-bottom: 40px;
}
@media (max-width: 800px) { .etd-actions-row { grid-template-columns: repeat(2, 1fr); } }
.etd-action {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    padding: 16px 18px;
    text-decoration: none; color: var(--etd-ink);
    display: flex; flex-direction: column; gap: 6px;
    transition: border-color .15s, transform .15s;
}
.etd-action:hover { border-color: var(--etd-ink-faint); transform: translateY(-1px); text-decoration: none; }
.etd-action .etd-ic {
    width: 32px; height: 32px; border-radius: var(--etd-radius);
    background: var(--etd-primary-soft); color: var(--etd-primary);
    display: inline-flex; align-items: center; justify-content: center;
    margin-bottom: 8px;
}
.etd-action-title { font-weight: 600; font-size: 14.5px; }
.etd-action-sub   { font-size: 12.5px; color: var(--etd-ink-quiet); }

/* ============================================================
   Panels + table-like rows
   ============================================================ */
/* Panel - matches the Tailwind bg-n-0 rounded-xl border-n-100
   shadow-card panels used across the ported views so a page that
   still uses .etd-panel (review-detail's Decision + Reviewers +
   Comments, series tree wrapper, doc-view files/versions pane)
   reads as the same panel family without needing per-panel Tailwind
   port work.  Every existing markup site picks up the new look
   automatically. */
.etd-panel {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: 12px;
    margin-bottom: 20px;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(14, 18, 24, 0.04), 0 4px 12px rgba(14, 18, 24, 0.06);
}
.etd-panel-head {
    padding: 16px 20px;
    border-bottom: 1px solid var(--etd-rule);
    display: flex; align-items: center; gap: 12px;
    background: var(--etd-surface);
}
.etd-panel-head h2 { font-size: 16px; font-weight: 600; letter-spacing: -0.005em; color: var(--etd-ink); margin: 0; }

/* Disabled panel - used when a section is visible-but-not-yet-usable
   (e.g. Reviewer information while the review is still queued behind
   a division-chair / SAC / EB pre-approval). Dims the body,
   disables all interaction (buttons, inputs, links) below the head,
   and shows a small "locked" callout at the top so the reader
   understands why they can't act. The panel head + heading stay at
   full opacity so the section is still discoverable. */
.etd-panel-disabled > *:not(.etd-panel-head):not(.etd-panel-locked-note) {
    opacity: 0.45;
    pointer-events: none;
    filter: grayscale(0.35);
    user-select: none;
}
.etd-panel-disabled input,
.etd-panel-disabled button,
.etd-panel-disabled select,
.etd-panel-disabled textarea {
    cursor: not-allowed;
}
.etd-panel-locked-note {
    padding: 10px 22px;
    background: var(--etd-primary-soft);
    color: var(--etd-primary-ink);
    font-size: 12.5px;
    border-bottom: 1px solid color-mix(in srgb, var(--etd-primary) 20%, transparent);
}
.etd-panel-locked-note::before {
    content: '🔒';
    margin-right: 6px;
    font-size: 12px;
    vertical-align: -1px;
}
.etd-panel-head-meta { margin-left: auto; font-size: 12.5px; color: var(--etd-ink-quiet); }

/* Policy callout - a soft info panel that surfaces policy text
   next to a form control, so the submitter doesn't have to leave
   the page to check ET-0297A-24. Rendered as a <details> so it's
   collapsible. */
.etd-policy-callout {
    background: var(--etd-primary-soft);
    border: 1px solid color-mix(in srgb, var(--etd-primary) 25%, transparent);
    border-radius: var(--etd-radius-md);
    padding: 10px 14px;
    margin: 8px 0 12px;
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--etd-primary-ink);
}
.etd-policy-callout > summary {
    cursor: pointer;
    list-style: none;
    font-size: 12px;
    color: var(--etd-primary-ink);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 2px 0;
}
.etd-policy-callout > summary::-webkit-details-marker { display: none; }
.etd-policy-callout > summary::marker { content: ""; }
.etd-policy-callout > summary::before {
    content: '▾';
    display: inline-block;
    width: 12px;
    margin-right: 4px;
    transition: transform 120ms ease;
}
.etd-policy-callout:not([open]) > summary::before { transform: rotate(-90deg); }
.etd-policy-callout-body { margin-top: 10px; }
.etd-policy-callout-body p { margin: 0 0 8px; }
.etd-policy-callout-body ul { margin: 0 0 12px; padding-left: 18px; }
.etd-policy-callout-body li { margin: 3px 0; }
.etd-policy-callout-body ul:last-child { margin-bottom: 0; }

/* Decision-panel overview list - one row per approval gate. */
.etd-decision-list { list-style: none; margin: 0; padding: 0; }
.etd-decision-row {
    display: grid;
    grid-template-columns: 24px 1fr auto;
    gap: 10px;
    align-items: baseline;
    padding: 8px 0;
    border-top: 1px dashed var(--etd-rule);
    font-size: 13.5px;
}
.etd-decision-row:first-child { border-top: 0; }
.etd-decision-icon {
    text-align: center;
    font-size: 13px;
    font-weight: 700;
    color: var(--etd-ink-quiet);
    line-height: 1;
    align-self: center;
}
.etd-decision-label { color: var(--etd-ink); font-weight: 500; }
.etd-decision-status {
    color: var(--etd-ink-quiet);
    font-size: 12.5px;
    text-align: right;
}

.etd-decision-row-done .etd-decision-icon    { color: var(--etd-good); }
.etd-decision-row-done .etd-decision-status  { color: var(--etd-good); }
.etd-decision-row-current                    { background: color-mix(in srgb, var(--etd-primary) 5%, transparent); border-radius: var(--etd-radius-sm); padding-left: 6px; padding-right: 6px; }
.etd-decision-row-current .etd-decision-icon    { color: var(--etd-primary); }
.etd-decision-row-current .etd-decision-label   { font-weight: 700; }
.etd-decision-row-current .etd-decision-status  { color: var(--etd-primary); font-weight: 600; }
.etd-decision-row-rejected .etd-decision-icon   { color: var(--etd-crit); }
.etd-decision-row-rejected .etd-decision-status { color: var(--etd-crit); font-weight: 600; }
.etd-decision-row-skipped .etd-decision-status  { color: var(--etd-ink-faint); font-style: italic; }
.etd-decision-row-future .etd-decision-icon     { color: var(--etd-ink-faint); }
.etd-decision-row-future .etd-decision-label    { color: var(--etd-ink-quiet); }
.etd-decision-row-future .etd-decision-status   { color: var(--etd-ink-faint); font-style: italic; }
.etd-row {
    display: grid; align-items: center;
    padding: 12px 22px;
    border-bottom: 1px solid var(--etd-rule);
    transition: background .12s;
}
.etd-row:last-child { border-bottom: 0; }
.etd-row:hover { background: var(--etd-bg-alt); }
.etd-row-h { color: var(--etd-ink-quiet); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; padding: 10px 22px; background: var(--etd-bg-alt); border-bottom: 1px solid var(--etd-rule); }
.etd-row-reviews   { grid-template-columns: 90px minmax(0, 1.2fr) minmax(220px, 1fr) 140px 110px minmax(180px, auto); gap: 14px; }
.etd-row-docs      { grid-template-columns: 110px 1fr 130px 120px 100px; gap: 16px; }
.etd-row-codifier  { grid-template-columns: 110px 1fr 180px 120px minmax(220px, 1fr); gap: 14px; }
.etd-row-title     { font-weight: 500; color: var(--etd-ink); }
.etd-row-title-sub { font-size: 12.5px; color: var(--etd-ink-quiet); margin-top: 2px; }
.etd-scope .etd-row-title-link { color: var(--etd-ink); text-decoration: none; border-bottom: 1px solid transparent; transition: border-color 120ms ease; }
.etd-scope .etd-row-title-link:hover { border-bottom-color: var(--etd-primary); color: var(--etd-primary); }

/* ============================================================
   Pipeline pills + state chips
   ============================================================ */
.etd-pip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 9px 3px 6px;
    border-radius: 999px;
    color: white; font-size: 11.5px; font-weight: 600;
    letter-spacing: 0.02em;
}
.etd-pip .etd-pip-code { padding: 1px 6px; background: rgba(255,255,255,.18); border-radius: 999px; font: 11px/1 var(--etd-mono); }
.etd-pip .etd-pip-name { font-weight: 500; letter-spacing: 0; white-space: nowrap; }
.etd-pip-p1  { background: var(--etd-p1); }
.etd-pip-p2  { background: var(--etd-p2); }
.etd-pip-p3  { background: var(--etd-p3); }
.etd-pip-p4  { background: var(--etd-p4); }
.etd-pip-p5  { background: var(--etd-p5); }
.etd-pip-p5b { background: var(--etd-p5b); }
.etd-pip-p6  { background: var(--etd-p6); }
.etd-pip-p7  { background: var(--etd-p7); }

/* ============================================================
   Pipeline stepper - vertical policy-order procession on the
   review-detail page. Each phase = one row; a linear opacity ramp
   walks from lightest (early phases) to fullest (concluding phase)
   in the pipeline's own colour, so the shape of the procedure is
   visible at a glance. The active phase gets a ring + bold label;
   completed phases carry a check mark inside the dot; still-to-come
   phases render outlined at the ramp opacity. Closed reviews dim
   the whole column to signal end of flow.
   ============================================================ */
.etd-review-detail-grid { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 32px; align-items: start; }
@media (max-width: 1024px) { .etd-review-detail-grid { grid-template-columns: 1fr; } }
.etd-review-detail-main { min-width: 0; }
.etd-review-detail-side { position: sticky; top: 20px; }

.etd-pipeline-stepper {
    --etd-step-color: var(--etd-p1);
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    padding: 18px 20px 22px;
}
.etd-pipeline-stepper-p1  { --etd-step-color: var(--etd-p1);  }
.etd-pipeline-stepper-p2  { --etd-step-color: var(--etd-p2);  }
.etd-pipeline-stepper-p3  { --etd-step-color: var(--etd-p3);  }
.etd-pipeline-stepper-p4  { --etd-step-color: var(--etd-p4);  }
.etd-pipeline-stepper-p5  { --etd-step-color: var(--etd-p5);  }
.etd-pipeline-stepper-p5b { --etd-step-color: var(--etd-p5b); }
.etd-pipeline-stepper-p6  { --etd-step-color: var(--etd-p6);  }
.etd-pipeline-stepper-p7  { --etd-step-color: var(--etd-p7);  }
.etd-pipeline-stepper-closed { opacity: 0.72; }

.etd-pipeline-stepper-head { margin-bottom: 14px; }
.etd-pipeline-stepper-title { font-size: 13.5px; font-weight: 600; color: var(--etd-ink); margin-top: 2px; line-height: 1.35; }

.etd-pipeline-steps { list-style: none; margin: 0; padding: 0; }
/* Phase divider - a tiny uppercase label between clusters of
   step-cards so the phase grouping is still legible even though
   every workflow step now has its own container. */
.etd-pipeline-phase-divider {
    font: 600 10px/1 var(--etd-sans);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--etd-step-color) 65%, var(--etd-ink-quiet));
    padding: 4px 4px 6px;
    margin-top: 14px;
}
.etd-pipeline-phase-divider:first-child { margin-top: 0; }
.etd-pipeline-phase-divider + .etd-pipeline-step { margin-top: 0; }
/* No arrowed connector below the last step of a phase - the phase
   divider label + margin acts as the visual separator, and a
   dangling arrow beneath it looks like a broken chain. */
.etd-pipeline-step:has(+ .etd-pipeline-phase-divider)::after,
.etd-pipeline-step:has(+ .etd-pipeline-phase-divider)::before { display: none; }
/* Each phase renders as its own card so the pipeline reads as a
   linked chain of stages rather than a single vertical list. A
   short arrowed connector sits below every card except the last,
   so direction of flow is unmistakable. The current-phase card
   picks up a thicker coloured border and a small "Current" tag. */
.etd-pipeline-step {
    display: block;
    padding: 0;
    background: var(--etd-surface);
    border: 1px solid color-mix(in srgb, var(--etd-step-color) 20%, var(--etd-rule));
    border-radius: var(--etd-radius-md);
    position: relative;
}
/* Match the card's rounded corners on the disclosed explain body so
   the bottom edge doesn't leave a notch when a card is open. */
.etd-pipeline-step .etd-pipeline-step-explain {
    border-radius: 0 0 calc(var(--etd-radius-md) - 1px) calc(var(--etd-radius-md) - 1px);
}
/* Click-to-expand shell - <details> + <summary> so no JS is needed
   for the disclosure. The whole summary row is clickable; the
   chevron rotates when the panel is open. */
.etd-pipeline-step-details { }
.etd-pipeline-step-details > summary {
    list-style: none;              /* remove native marker */
    display: grid;
    grid-template-columns: 24px 1fr 16px;
    gap: 10px;
    align-items: center;
    padding: 12px 14px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.etd-pipeline-step-details > summary::-webkit-details-marker { display: none; }
.etd-pipeline-step-details > summary::marker { content: ""; }
.etd-pipeline-step-details > summary:hover .etd-pipeline-step-label { color: var(--etd-primary); }
.etd-pipeline-step-chevron {
    color: color-mix(in srgb, var(--etd-step-color) 65%, var(--etd-ink-quiet));
    font-size: 12px;
    transition: transform 120ms ease;
    line-height: 1;
    text-align: center;
}
.etd-pipeline-step-details[open] > summary > .etd-pipeline-step-chevron {
    transform: rotate(90deg);
}
.etd-pipeline-step-explain {
    padding: 4px 16px 14px 48px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--etd-ink-quiet);
    border-top: 1px dashed color-mix(in srgb, var(--etd-step-color) 20%, var(--etd-rule));
    background: color-mix(in srgb, var(--etd-step-color) 3%, var(--etd-surface));
    margin-top: 4px;
}
.etd-pipeline-step-explain p { margin: 8px 0 0; }
.etd-pipeline-step-explain ul { margin: 8px 0 0; padding-left: 18px; }
.etd-pipeline-step-explain li { margin: 3px 0; }
.etd-pipeline-step-explain strong { color: var(--etd-ink); font-weight: 600; }
.etd-pipeline-step-explain em { color: var(--etd-ink); font-style: italic; }
.etd-pipeline-step + .etd-pipeline-step { margin-top: 22px; }
/* Connector after every step except the last - vertical line
   ending in an arrow head, sitting in the gap above the next
   card. Rendered in the pipeline colour so it visually tows the
   cards together. */
.etd-pipeline-step:not(:last-child)::after {
    content: '';
    position: absolute;
    left: 26px;
    bottom: -19px;
    width: 2px;
    height: 12px;
    background: color-mix(in srgb, var(--etd-step-color) 55%, transparent);
    z-index: 1;
}
.etd-pipeline-step:not(:last-child)::before {
    content: '';
    position: absolute;
    left: 21px;
    bottom: -22px;
    width: 0; height: 0;
    border-left: 6px solid transparent;
    border-right: 6px solid transparent;
    border-top: 6px solid color-mix(in srgb, var(--etd-step-color) 55%, transparent);
    z-index: 2;
}
.etd-pipeline-step-dot {
    width: 20px; height: 20px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--etd-step-color) calc(var(--etd-step-fill, 1) * 100%), transparent);
    transition: box-shadow 120ms ease;
    margin-top: 1px;
    align-self: start;
    justify-self: center;
}
.etd-pipeline-step-body { min-width: 0; }
.etd-pipeline-step-label {
    font-size: 13.5px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--etd-ink);
    display: block;
}
.etd-pipeline-step-actions {
    list-style: none;
    margin: 6px 0 4px;
    padding: 0;
    font-size: 12px;
    line-height: 1.45;
    color: var(--etd-ink-quiet);
}
.etd-pipeline-step-actions li {
    padding: 2px 0 2px 12px;
    position: relative;
}
.etd-pipeline-step-actions li::before {
    content: '';
    position: absolute;
    left: 2px; top: 8px;
    width: 4px; height: 4px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--etd-step-color) 45%, transparent);
}
/* Workflow sub-step states - used by the reviewer-lifecycle bullets
   (standard-ec-review, minor-ec-review). */
.etd-pipeline-substep-past    { color: var(--etd-ink-quiet); }
.etd-pipeline-substep-past::before    { background: color-mix(in srgb, var(--etd-step-color) 65%, transparent); }
.etd-pipeline-substep-current { color: var(--etd-ink); font-weight: 600; }
.etd-pipeline-substep-current::before {
    content: '';
    left: 0; top: 6px;
    width: 8px; height: 8px;
    background: var(--etd-step-color);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--etd-step-color) 25%, transparent);
}
.etd-pipeline-substep-future::before  { background: color-mix(in srgb, var(--etd-step-color) 30%, transparent); }
/* Nested sub-state annotation under a workflow step (e.g. "Changes
   requested - awaiting author response" beneath the EC-decides step). */
.etd-pipeline-substep-sub {
    display: block;
    margin-top: 3px;
    font-size: 11.5px;
    font-weight: 400;
    color: var(--etd-ink-quiet);
    font-style: italic;
}
/* Future-phase action bullets sit quieter; done-phase actions
   render a shade darker because they belong to a resolved phase. */
.etd-pipeline-step-future .etd-pipeline-step-actions { opacity: 0.7; }
.etd-pipeline-step-done   .etd-pipeline-step-actions { color: var(--etd-ink); }
.etd-pipeline-step-current .etd-pipeline-step-actions { color: var(--etd-ink); }

/* Done card - filled with a tint of the pipeline colour, still clearly
   distinct from the current one. */
.etd-pipeline-step-done {
    background: color-mix(in srgb, var(--etd-step-color) 6%, var(--etd-surface));
    border-color: color-mix(in srgb, var(--etd-step-color) 35%, var(--etd-rule));
}
.etd-pipeline-step-done .etd-pipeline-step-label { color: var(--etd-ink); }

/* Current card - thick coloured border, subtle fill in the pipeline
   colour, a soft outer glow, and a "Current" tag that reads at a
   glance. Impossible to miss which phase the review is at. */
.etd-pipeline-step-current {
    background: color-mix(in srgb, var(--etd-step-color) 8%, var(--etd-surface));
    border: 2px solid var(--etd-step-color);
    padding: 11px 13px;  /* compensate for the thicker border */
    box-shadow: 0 4px 14px color-mix(in srgb, var(--etd-step-color) 22%, transparent);
}
.etd-pipeline-step-current::before,
.etd-pipeline-step-current::after {
    /* Connector below the current card gets a matching thicker
       colour so the flow reads continuous. */
    background: var(--etd-step-color);
}
.etd-pipeline-step-current::before {
    border-top-color: var(--etd-step-color);
}
.etd-pipeline-step-current .etd-pipeline-step-body::after {
    content: 'Current';
    position: absolute;
    top: -10px;
    right: 12px;
    background: var(--etd-step-color);
    color: white;
    font: 600 10px/1 var(--etd-sans);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 999px;
}
.etd-pipeline-step-current .etd-pipeline-step-dot {
    box-shadow: 0 0 0 2px var(--etd-surface),
                0 0 0 4px color-mix(in srgb, var(--etd-step-color) 55%, transparent);
    background: var(--etd-step-color);
}
.etd-pipeline-step-current .etd-pipeline-step-label {
    color: var(--etd-ink);
    font-weight: 700;
}

/* Future card - outlined, mildly opaque so the not-yet-live phases
   read as forthcoming. */
.etd-pipeline-step-future { opacity: 0.72; }
.etd-pipeline-step-future .etd-pipeline-step-dot {
    background: var(--etd-surface);
    border: 1.5px solid color-mix(in srgb, var(--etd-step-color) calc(var(--etd-step-fill, 1) * 100%), transparent);
    box-shadow: 0 0 0 2px var(--etd-surface);
}

.etd-chip {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 2px 9px; border-radius: 999px;
    background: var(--etd-bg);
    border: 1px solid var(--etd-rule);
    font-size: 11.5px; font-weight: 500;
    color: var(--etd-ink-quiet);
}
.etd-chip .etd-stip { width: 6px; height: 6px; border-radius: 50%; background: var(--etd-ink-faint); }
.etd-chip-open    { color: var(--etd-good); border-color: #BFE0CC; background: var(--etd-good-soft); }
.etd-chip-open    .etd-stip { background: var(--etd-good); }
/* Under-review: referees finished, EC decision pending.  Blue,
   distinct from `open` (green, referees still working) and from
   `approved` (green, terminal). */
.etd-chip-under-review { color: #1f4e8f; border-color: #b8ceec; background: #eaf2fb; }
.etd-chip-under-review .etd-stip { background: #3a7ac2; }
.etd-chip-approved { color: var(--etd-good); border-color: #BFE0CC; background: var(--etd-good-soft); font-weight: 600; }
.etd-chip-approved .etd-stip { background: var(--etd-good); }
.etd-chip-due     { color: var(--etd-warn); border-color: #E6CE9C; background: var(--etd-warn-soft); }
.etd-chip-due     .etd-stip { background: var(--etd-warn); }
.etd-chip-blocked { color: var(--etd-crit); border-color: #ECC0BE; background: var(--etd-crit-soft); }
.etd-chip-blocked .etd-stip { background: var(--etd-crit); }
/* Final-status chips on the closed-reviews listing. `rejected`
   reuses the crit palette so the row reads as terminal-failed
   at a glance; `withdrawn` gets a neutral grey since it's not
   a failure - just out-of-scope. */
.etd-chip-rejected  { color: var(--etd-crit); border-color: #ECC0BE; background: var(--etd-crit-soft); font-weight: 600; }
.etd-chip-rejected  .etd-stip { background: var(--etd-crit); }
.etd-chip-withdrawn { color: #4b5563; border-color: #cfd6de; background: #eef1f5; font-weight: 600; }
.etd-chip-withdrawn .etd-stip { background: #8a96a5; }
/* Reviewer-information panel: distinct chips for the "active
   reviewer" states so a reader can tell at a glance whether a
   reviewer is still to respond, is actively reviewing, or is a
   backup standing by.  Blue = in progress (mirrors etd-chip-under-
   review on the reviews listing); grey = backup on standby. */
.etd-chip-in-progress    { color: #1f4e8f; border-color: #b8ceec; background: #eaf2fb; font-weight: 600; }
.etd-chip-in-progress    .etd-stip { background: #3a7ac2; }
.etd-chip-backup-standby { color: #4b5563; border-color: #d0d7de; background: #f1f4f8; font-weight: 600; }
.etd-chip-backup-standby .etd-stip { background: #8a96a5; }

.etd-deadline { font-size: 13px; color: var(--etd-ink); font-variant-numeric: tabular-nums; }
.etd-deadline-soon    { color: var(--etd-warn); font-weight: 600; }
.etd-deadline-overdue { color: var(--etd-crit); font-weight: 600; }

/* Sparkline (consumed inline as <svg class="etd-sparkline">) */
.etd-sparkline { display: inline-block; vertical-align: middle; }
.etd-sparkline path.line { stroke: var(--etd-primary); fill: none; stroke-width: 1.5; }
.etd-sparkline path.area { fill: var(--etd-primary); opacity: 0.08; }
.etd-sparkline circle    { fill: var(--etd-primary); }

/* ============================================================
   Filter chips (codifier listing)
   ============================================================ */
.etd-filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 24px; }
.etd-filter-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 10px 5px 12px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: 999px;
    background: var(--etd-surface);
    color: var(--etd-ink);
    font-size: 13px;
    cursor: pointer;
    transition: border-color .12s;
}
.etd-filter-chip:hover { border-color: var(--etd-ink-faint); }
.etd-filter-chip-active {
    border-color: var(--etd-primary);
    background: var(--etd-primary-soft);
    color: var(--etd-primary-ink);
}
.etd-filter-divider { width: 1px; background: var(--etd-rule); margin: 0 4px; }

/* ============================================================
   Document detail - header + tabs + body
   ============================================================ */
.etd-doc-header {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg) var(--etd-radius-lg) 0 0;
    padding: 28px 32px;
}
.etd-doc-header-top  { display: flex; gap: 14px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
.etd-doc-header h1   { font-size: 30px; line-height: 1.2; letter-spacing: -0.015em; margin-bottom: 10px; }
.etd-doc-header-meta { font-size: 14px; color: var(--etd-ink-quiet); display: flex; gap: 8px; flex-wrap: wrap; }
.etd-doc-header-meta .etd-sep { color: var(--etd-ink-faint); }
.etd-doc-header-actions { margin-top: 18px; display: flex; gap: 10px; flex-wrap: wrap; }

/* Tabs - flat underline-on-active pattern matching etmd-next's
   navigation tabs.  Used by the doc-view (Overview / Files /
   Versions / Review / History) and review-detail (Review /
   History) tab bars.  The .etd-tabs container styling was
   moved to the calling Tailwind wrapper (flex + gap + border-b)
   so this rule now handles just the tab item + active state. */
.etd-tabs {
    padding: 0;
    display: flex; gap: 4px;
    background: transparent;
    border: 0;
}
.etd-tab {
    padding: 10px 14px;
    font-size: 14px; font-weight: 500;
    color: var(--etd-ink-quiet);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;   /* overlap the container's border-b so active underline replaces it */
    cursor: pointer;
    transition: color .12s, border-color .12s, background .12s;
    text-decoration: none;
    border-radius: 6px 6px 0 0;
}
.etd-tab:hover { color: var(--etd-ink); background: var(--etd-bg-alt); text-decoration: none; }
.etd-tab-active { color: var(--etd-primary); border-bottom-color: var(--etd-primary); font-weight: 600; background: transparent; }
.etd-tab-active:hover { background: transparent; }
.etd-tab-count {
    margin-left: 6px;
    font-size: 11px; font-weight: 600;
    color: var(--etd-ink-quiet);
    background: var(--etd-bg);
    padding: 1px 7px; border-radius: 999px;
    font-variant-numeric: tabular-nums;
    display: inline-block;
}
.etd-tab-active .etd-tab-count {
    background: var(--etd-primary-soft);
    color: var(--etd-primary-ink);
}
.etd-doc-body {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule); border-top: 1px solid var(--etd-rule);
    border-radius: 0 0 var(--etd-radius-lg) var(--etd-radius-lg);
    padding: 32px;
    display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: 40px;
}
@media (max-width: 1024px) { .etd-doc-body { grid-template-columns: 1fr; } }
.etd-doc-main h2 { margin: 20px 0 10px; }
.etd-doc-main h2:first-child { margin-top: 0; }
.etd-doc-main p  { color: var(--etd-ink); line-height: 1.65; }
.etd-doc-main p + p { margin-top: 12px; }
.etd-doc-aside { display: flex; flex-direction: column; gap: 22px; }
.etd-aside-block .etd-label-up { display: block; margin-bottom: 6px; }
.etd-aside-block .etd-val { font-size: 14px; color: var(--etd-ink); word-break: break-word; }
.etd-aside-block .etd-val.etd-mono { font-family: var(--etd-mono); }

/* Files list inside .etd-doc-main - .etd-doc-files wraps the
   Files::build_files_for_output HTML. Each file is its own
   .etd-doc-file-row: icon + thumbnail + name on the left,
   size + download/delete actions pushed to the right, so the
   row spans the full container width (matters most for outreach
   documents, where the files pane is the main content). */
.etd-doc-files {
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    padding: 8px 16px;
    font-size: 14px;
}
.etd-doc-files a { color: var(--etd-primary); }
.etd-doc-files a:hover { color: var(--etd-primary-hover); }
.etd-doc-files i.fa { color: var(--etd-ink-quiet); margin-right: 4px; }
.etd-doc-files img { border-radius: 3px; border: 1px solid var(--etd-rule); }

.etd-doc-file-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 8px 0;
    border-bottom: 1px solid var(--etd-rule);
    min-width: 0;
}
.etd-doc-file-row:last-child { border-bottom: 0; }
.etd-doc-file-main {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1 1 auto;
    min-width: 0;
}
.etd-doc-file-main .etd-doc-file-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.etd-doc-file-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
    color: var(--etd-ink-quiet);
    white-space: nowrap;
}
.etd-doc-file-meta .etd-doc-file-size {
    font-variant-numeric: tabular-nums;
    font-size: 13px;
}
/* Download button next to each filename - small ghost pill that
   lights up on hover so it reads as an action, not decoration. */
.etd-doc-files .etd-file-dl {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px;
    border-radius: 4px;
    color: var(--etd-ink-quiet) !important;
    text-decoration: none !important;
    transition: background .12s, color .12s;
    margin: 0 4px;
    vertical-align: -2px;
}
.etd-doc-files .etd-file-dl:hover {
    background: var(--etd-primary-soft);
    color: var(--etd-primary) !important;
}
.etd-doc-files .etd-file-dl i.fa { margin: 0; font-size: 12px; color: inherit !important; }

/* Delete button - same shape as .etd-file-dl but with a danger
   hover state so it reads as destructive at a glance. Cursor
   pointer + role/tabindex on the anchor for keyboard access. */
.etd-doc-files .etd-file-del {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px;
    border-radius: 4px;
    color: var(--etd-ink-quiet) !important;
    text-decoration: none !important;
    cursor: pointer;
    transition: background .12s, color .12s;
    margin: 0 4px;
    vertical-align: -2px;
}
.etd-doc-files .etd-file-del:hover {
    background: #FCEDED;
    color: #B94141 !important;
}
.etd-doc-files .etd-file-del i.fa { margin: 0; font-size: 12px; color: inherit !important; }

/* Doc-detail tab panes. Only the active pane is visible; the
   others carry [hidden] plus a display:none fallback for older
   browsers. JS in docs.js#switch_doc_tab handles the swap. */
.etd-doc-pane { display: none; }
.etd-doc-pane[hidden] { display: none; }
.etd-doc-pane-active { display: block !important; }
.etd-doc-pane > h2:first-child { margin-top: 0; }
.etd-doc-pane > h2 { margin: 20px 0 10px; }

/* Codifier density toggle. Two-button segmented control that
   flips the .etd-codifier-list between comfortable + compact row
   heights. Preference persists in localStorage (see docs.js). */
.etd-density-toggle {
    display: inline-flex;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius-sm);
    overflow: hidden;
    background: var(--etd-surface);
}
.etd-density-btn {
    appearance: none;
    width: 34px; height: 34px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent;
    color: var(--etd-ink-quiet);
    border: 0;
    cursor: pointer;
    transition: background .12s, color .12s;
    padding: 0;
}
.etd-density-btn + .etd-density-btn {
    border-left: 1px solid var(--etd-rule-strong);
}
.etd-density-btn:hover {
    color: var(--etd-ink);
    background: var(--etd-bg-alt);
}
.etd-density-btn-active {
    background: var(--etd-primary) !important;
    color: white !important;
}
/* Compact-mode adjustments - tighter row padding + smaller sparkline.
   Applied when the JS sets .etd-density-mode-compact on the list. */
.etd-codifier-list.etd-density-mode-compact .etd-row-codifier {
    padding-top: 6px !important;
    padding-bottom: 6px !important;
    min-height: 0 !important;
    font-size: 12.5px;
}
.etd-codifier-list.etd-density-mode-compact .etd-row-codifier .etd-doctype {
    font-size: 10px;
    padding: 2px 6px;
}
.etd-codifier-list.etd-density-mode-compact .etd-row-codifier .etd-sparkline {
    width: 44px; height: 14px;
}
.etd-codifier-list.etd-density-mode-compact .etd-row-h {
    padding-top: 8px !important;
    padding-bottom: 8px !important;
}

/* Version timeline - horizontal axis with one dot per release,
   sits above the Versions pane's release cards. Current release
   dot is filled primary blue and its letter label sits above; the
   others are outlined with the label below, so the "you are here"
   marker is unmistakable at a glance. */
.etd-doc-timeline {
    margin: 6px 0 20px;
    padding: 12px 8px 6px;
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
}
.etd-doc-timeline svg { display: block; }
.etd-doc-timeline-lbl {
    font: 700 10px/1 var(--etd-mono);
    fill: var(--etd-ink-quiet);
    letter-spacing: 0.05em;
}
.etd-doc-timeline-lbl-current {
    fill: var(--etd-primary-ink);
}
.etd-doc-timeline-axis {
    display: flex; justify-content: space-between;
    padding: 4px 12px 0;
    font: 500 10.5px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
}

/* Versions section - one row per release of the current code. */
.etd-doc-versions {
    display: flex; flex-direction: column;
    gap: 8px;
    margin-top: 8px;
}
.etd-doc-version {
    display: grid;
    grid-template-columns: 44px 1fr auto;
    gap: 14px;
    padding: 12px 14px;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    text-decoration: none !important;
    color: inherit;
    transition: border-color .12s, box-shadow .12s;
    align-items: center;
}
.etd-doc-version:hover {
    border-color: var(--etd-ink-faint);
    box-shadow: 0 4px 12px rgba(10, 21, 37, .06);
}
.etd-doc-version-current {
    border-color: var(--etd-primary);
    background: var(--etd-primary-soft);
    pointer-events: none;
}
.etd-doc-version-current:hover {
    box-shadow: none;
}
.etd-doc-version-letter {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px;
    border-radius: 50%;
    background: var(--etd-bg-alt);
    color: var(--etd-primary-ink);
    font: 700 13px/1 var(--etd-mono);
    border: 1px solid var(--etd-rule);
    flex-shrink: 0;
}
.etd-doc-version-current .etd-doc-version-letter {
    background: var(--etd-primary);
    color: white;
    border-color: var(--etd-primary);
}
.etd-doc-version-body {
    display: flex; flex-direction: column; gap: 3px;
    min-width: 0;
}
.etd-doc-version-title {
    font: 600 13.5px/1.3 var(--etd-sans);
    color: var(--etd-ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.etd-doc-version-meta {
    font: 500 11.5px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    letter-spacing: 0.02em;
}
.etd-doc-version-tags {
    display: inline-flex; gap: 4px; flex-shrink: 0;
}
.etd-doc-version-tag {
    font: 700 9.5px/1 var(--etd-mono);
    letter-spacing: 0.08em;
    padding: 3px 7px;
    border-radius: var(--etd-radius-sm);
    text-transform: uppercase;
}
.etd-doc-version-tag-current {
    background: var(--etd-primary);
    color: white;
}
.etd-doc-version-tag-latest {
    background: transparent;
    color: var(--etd-accent);
    border: 1px solid var(--etd-accent);
}
/* Older versions expander - <details> collapsed by default; on
   [open] the label swaps ("Show N" → "Hide N") and the chevron
   rotates. Body inherits the same row layout as the visible
   current-release card. */
.etd-doc-versions-more { margin-top: 4px; }
.etd-doc-versions-more-toggle {
    list-style: none;
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 12px;
    background: transparent;
    border: 1px dashed var(--etd-rule-strong);
    border-radius: var(--etd-radius);
    color: var(--etd-ink-quiet);
    font: 500 12.5px/1 var(--etd-sans);
    cursor: pointer;
    transition: border-color .12s, color .12s;
    user-select: none;
    width: 100%;
    justify-content: center;
}
.etd-doc-versions-more-toggle::-webkit-details-marker { display: none; }
.etd-doc-versions-more-toggle:hover {
    border-color: var(--etd-primary);
    color: var(--etd-primary);
}
.etd-doc-versions-more-chev {
    width: 8px; height: 8px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    transition: transform .15s;
    display: inline-block;
    vertical-align: 1px;
}
.etd-doc-versions-more[open] .etd-doc-versions-more-chev {
    transform: rotate(-135deg);
}
/* Label swap: two spans in the summary, one visible per state. */
.etd-doc-versions-more[open] .etd-doc-versions-more-label-closed,
.etd-doc-versions-more:not([open]) .etd-doc-versions-more-label-open {
    display: none;
}
.etd-doc-versions-more-body {
    display: flex; flex-direction: column;
    gap: 8px;
    margin-top: 8px;
}

/* Review section - either the full state grid or a "not yet
   submitted" placeholder with a submit CTA. */
.etd-doc-review-empty {
    padding: 20px 22px;
    background: var(--etd-bg-alt);
    border: 1px dashed var(--etd-rule-strong);
    border-radius: var(--etd-radius-lg);
    display: flex; flex-direction: column; gap: 8px;
}
.etd-doc-review-empty-title {
    font: 600 14px/1.4 var(--etd-sans);
    color: var(--etd-ink) !important;
    margin: 0 !important;
}
.etd-doc-review-empty-hint {
    font-size: 13px;
    color: var(--etd-ink-quiet);
    margin: 0 !important;
    max-width: 60ch;
    line-height: 1.5;
}
.etd-doc-review-empty > div:last-child { margin-top: 6px; }
.etd-doc-review-state {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 14px 20px;
    padding: 18px 20px;
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    margin-top: 8px;
}
.etd-doc-review-row {
    display: flex; flex-direction: column; gap: 6px;
}
.etd-doc-review-row .etd-label-up { display: block; }
.etd-doc-review-phase {
    display: inline-flex; align-items: center; gap: 10px;
    flex-wrap: wrap;
}
.etd-doc-review-deadline {
    font: 500 11.5px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    letter-spacing: 0.02em;
}
.etd-doc-review-hint {
    margin-top: 12px !important;
    font-size: 13px;
}
.etd-doc-review-hint a {
    color: var(--etd-primary);
    text-decoration: none;
}
.etd-doc-review-hint a:hover { text-decoration: underline; }

/* History timeline - audit trail of codifier events. Vertical
   spine on the left with a small primary-blue dot per event; the
   right column carries timestamp + actor + description. Legacy
   HTML in descriptions (w3-tag chips, icons) is preserved so the
   context reads through; scoped w3-tag overrides below keep the
   pills styled in v0.2. */
.etd-doc-history {
    list-style: none;
    padding: 0;
    margin: 12px 0 0 !important;
    position: relative;
    counter-reset: history-event;
}
.etd-doc-history::before {
    content: '';
    position: absolute;
    left: 6px; top: 6px; bottom: 6px;
    width: 2px;
    background: var(--etd-rule);
    border-radius: 1px;
}
.etd-doc-history-item {
    position: relative;
    display: grid;
    grid-template-columns: 14px 1fr;
    gap: 14px;
    padding: 8px 0 14px 0;
    align-items: start;
}
.etd-doc-history-item:last-child { padding-bottom: 4px; }
.etd-doc-history-marker {
    width: 14px; height: 14px;
    border-radius: 50%;
    background: var(--etd-surface);
    border: 3px solid var(--etd-primary);
    position: relative;
    z-index: 1;
    margin-top: 4px;
}
.etd-doc-history-item:first-child .etd-doc-history-marker {
    background: var(--etd-primary);
}
.etd-doc-history-body { min-width: 0; }
.etd-doc-history-meta {
    display: flex; align-items: baseline;
    gap: 12px; flex-wrap: wrap;
    margin-bottom: 4px;
}
.etd-doc-history-time {
    font: 600 12px/1 var(--etd-mono);
    color: var(--etd-ink);
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
}
.etd-doc-history-user {
    font: 500 11.5px/1 var(--etd-sans);
    color: var(--etd-ink-quiet);
    display: inline-flex; align-items: center; gap: 4px;
}
.etd-doc-history-user i.fa { font-size: 10px; }
.etd-doc-history-desc {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--etd-ink);
    word-break: break-word;
}
.etd-doc-history-desc i.fa {
    color: var(--etd-ink-quiet);
    margin-right: 4px;
}
/* Legacy w3-tag chips inside history descriptions - style them
   as inline pills so the visual context comes through v0.2. */
.etd-doc-history-desc .w3-tag {
    display: inline-block;
    font: 600 10.5px/1 var(--etd-mono);
    letter-spacing: 0.04em;
    padding: 3px 7px;
    border-radius: var(--etd-radius-sm);
    background: var(--etd-primary-soft);
    color: var(--etd-primary-ink);
    border: 1px solid var(--etd-primary-soft);
    margin: 0 2px;
    vertical-align: 1px;
}

/* Outreach material section on the doc detail. Status banner +
   3-col grid of the long-form fields + languages. */
.etd-doc-outreach-status {
    padding: 12px 16px;
    border-radius: var(--etd-radius);
    font-size: 13.5px;
    font-weight: 600;
    display: inline-flex; align-items: center; gap: 8px;
    margin-bottom: 16px;
}
.etd-doc-outreach-status-ok {
    background: var(--etd-good-soft, #E5F2EB);
    color: #1F6E5A;
    border: 1px solid #BFE2CD;
}
.etd-doc-outreach-status-warn {
    background: #FBF0DF;
    color: #C0691B;
    border: 1px solid #EAD3B4;
}
.etd-doc-outreach-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 16px 24px;
    padding: 16px 18px;
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
}
.etd-doc-outreach-grid > div .etd-label-up { display: block; margin-bottom: 6px; font-size: 10.5px; }
.etd-doc-outreach-grid > div p {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--etd-ink);
    margin: 0;
    word-break: break-word;
}

/* Access-level badges in the aside. */
.etd-doc-access-badge {
    display: inline-block;
    font: 700 10.5px/1 var(--etd-mono);
    letter-spacing: 0.05em;
    padding: 4px 8px;
    border-radius: var(--etd-radius-sm);
    background: var(--etd-primary-soft);
    color: var(--etd-primary-ink);
    border: 1px solid var(--etd-primary-soft);
    margin: 0 4px 4px 0;
}

/* Series paths - one line per path with the sitemap icon. */
.etd-doc-series-list { display: flex; flex-direction: column; gap: 6px; }
.etd-doc-series-row {
    font-size: 13px;
    line-height: 1.45;
    color: var(--etd-ink);
}
.etd-doc-series-row i.fa {
    color: var(--etd-primary);
    margin-right: 6px;
}
.etd-doc-series-row a {
    color: var(--etd-ink);
    text-decoration: none;
}
.etd-doc-series-row a:hover { color: var(--etd-primary); }

/* Referral URL - copy widget. Mono URL + pill copy button + a
   short "Copied" flash message that the copy_referral_url() JS
   toggles via the w3-hide class. */
.etd-doc-refurl-block .etd-doc-refurl {
    display: flex; align-items: center; gap: 8px;
    padding: 8px 10px;
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-sm);
    flex-wrap: wrap;
    max-width: 100%;
    box-sizing: border-box;
    overflow: hidden; /* last-resort containment against any exotic child that ignores wrap */
}
.etd-doc-refurl-value {
    flex: 1 1 100%;
    min-width: 0;
    max-width: 100%;
    font: 500 12px/1.4 var(--etd-mono);
    color: var(--etd-ink);
    /* Let the URL wrap and break inside long path segments so it
       never escapes the aside container.  overflow-wrap:anywhere
       handles browsers that don't respect word-break:break-all
       for URLs. */
    white-space: normal;
    word-break: break-all;
    overflow-wrap: anywhere;
}
.etd-doc-refurl-copy {
    appearance: none;
    padding: 6px 10px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: 999px;
    background: var(--etd-surface);
    color: var(--etd-ink-quiet);
    font: 600 11.5px/1 var(--etd-sans);
    cursor: pointer;
    display: inline-flex; align-items: center; gap: 4px;
    flex-shrink: 0;
    transition: border-color .12s, color .12s;
}
.etd-doc-refurl-copy:hover { border-color: var(--etd-primary); color: var(--etd-primary-ink); }
.etd-doc-refurl-copied {
    font: 700 10.5px/1 var(--etd-mono);
    letter-spacing: 0.08em;
    color: var(--etd-primary-ink);
    background: var(--etd-primary-soft);
    padding: 4px 8px;
    border-radius: var(--etd-radius-sm);
}

/* Other releases list - link rows with an optional LATEST tag. */
.etd-doc-other-releases { display: flex; flex-direction: column; gap: 4px; }
.etd-doc-other-release-row {
    font: 500 13px/1.4 var(--etd-sans);
}
.etd-doc-other-release-row a {
    color: var(--etd-primary);
    text-decoration: none;
}
.etd-doc-other-release-row a:hover { color: var(--etd-primary-hover); text-decoration: underline; }
.etd-doc-latest-tag {
    font: 700 9.5px/1 var(--etd-mono);
    letter-spacing: 0.08em;
    color: var(--etd-accent);
    background: transparent;
    padding: 3px 6px;
    border: 1px solid var(--etd-accent);
    border-radius: var(--etd-radius-sm);
    margin-left: 6px;
    vertical-align: 2px;
}

/* ============================================================
   Section divider (between mock sections / page sections)
   ============================================================ */
.etd-section-divider     { max-width: 1240px; margin: 24px auto 0; padding: 0 28px; }
.etd-section-divider-inner { border-top: 1px dashed var(--etd-rule-strong); padding-top: 40px; display: flex; align-items: baseline; gap: 14px; }
.etd-section-divider-num { font: 600 13px/1 var(--etd-mono); color: var(--etd-ink-faint); font-variant-numeric: tabular-nums; padding: 4px 8px; border: 1px solid var(--etd-rule-strong); border-radius: var(--etd-radius-sm); }
.etd-section-divider-label { font: 600 13px/1 var(--etd-sans); color: var(--etd-ink-quiet); letter-spacing: 0.04em; text-transform: uppercase; }

/* ============================================================
   FORM components (continued from v0.1 - palette updates above
   apply automatically via custom-property cascade)
   ============================================================ */
.etd-card { background: var(--etd-surface); border: 1px solid var(--etd-rule); border-radius: var(--etd-radius-lg); box-shadow: var(--etd-shadow-1); }
.etd-form { display: flex; flex-direction: column; }
.etd-field { display: flex; flex-direction: column; gap: 8px; padding: 24px 28px; border-bottom: 1px solid var(--etd-rule); }
.etd-field:last-of-type { border-bottom: 0; }
.etd-field-head     { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.etd-field-num      { font: 12px/1 var(--etd-mono); color: var(--etd-ink-faint); font-variant-numeric: tabular-nums; min-width: 22px; }
/* Presentation reviews (P5 / P5b) drop the field numbering:
   the block set changes shape mid-form (Event + presentation-flow
   blocks appear, Author-list type / Prior approval / etc do not),
   which makes a static "1., 2., 3., ..." sequence misleading.
   scripts/review_triage.js toggles this class on the form when
   the resolved pipeline is P5 / P5b. */
.etd-triage-no-nums .etd-field-num { display: none; }
.etd-field-label    { font-weight: 600; font-size: 15px; color: var(--etd-ink); }
.etd-field-required { font-size: 11px; font-weight: 600; color: var(--etd-accent); letter-spacing: 0.04em; text-transform: uppercase; }
.etd-field-hint     { font-size: 13px; color: var(--etd-ink-quiet); max-width: 60ch; }

.etd-input, .etd-select {
    appearance: none;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius);
    padding: 9px 12px;
    font: 14.5px/1.45 var(--etd-sans);
    color: var(--etd-ink);
    width: 100%;
    transition: border-color .12s, box-shadow .12s;
}
.etd-input:hover, .etd-select:hover { border-color: var(--etd-ink-faint); }
.etd-input:focus, .etd-select:focus { outline: 0; border-color: var(--etd-primary); box-shadow: 0 0 0 3px var(--etd-primary-soft); }
.etd-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none' stroke='%235A6477' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 12px center; padding-right: 32px;
}

/* Radios (pill-style) */
.etd-radio-row { display: flex; gap: 12px; flex-wrap: wrap; }
.etd-radio {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 14px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius);
    background: var(--etd-surface);
    cursor: pointer; font-size: 14px;
    transition: all .12s; user-select: none;
}
.etd-radio:hover { border-color: var(--etd-ink-faint); }
.etd-radio input { accent-color: var(--etd-primary); margin: 0; }
.etd-radio:has(input:checked) { border-color: var(--etd-primary); background: var(--etd-primary-soft); color: var(--etd-primary-ink); }

/* Radios (block-style with hint) */
.etd-radio-list  { display: flex; flex-direction: column; gap: 8px; }
.etd-radio-block {
    display: flex; align-items: flex-start; gap: 12px;
    padding: 10px 14px;
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    background: var(--etd-surface); cursor: pointer;
}
.etd-radio-block:hover { border-color: var(--etd-rule-strong); }
.etd-radio-block input { accent-color: var(--etd-primary); margin-top: 3px; }
.etd-radio-block:has(input:checked) { border-color: var(--etd-primary); background: var(--etd-primary-soft); }
.etd-rb-label { font-size: 14px; color: var(--etd-ink); display: block; }
.etd-rb-hint  { font-size: 12.5px; color: var(--etd-ink-quiet); margin-top: 2px; display: block; }

/* Reviewer typeahead */
.etd-reviewer-row     { display: grid; grid-template-columns: 80px 1fr auto; gap: 10px; align-items: start; position: relative; }
.etd-reviewer-row-lab { font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--etd-ink-quiet); padding-top: 11px; }
.etd-reviewer-clear   { appearance: none; padding: 8px 12px; border: 1px solid var(--etd-rule-strong); border-radius: var(--etd-radius); background: var(--etd-surface); color: var(--etd-ink-quiet); cursor: pointer; font: 13px/1 var(--etd-sans); }
.etd-reviewer-suggestions { background: var(--etd-surface); border: 1px solid var(--etd-rule-strong); border-radius: var(--etd-radius); box-shadow: var(--etd-shadow-2); margin-top: 4px; max-height: 240px; overflow-y: auto; }
.etd-reviewer-suggestion { padding: 8px 12px; cursor: pointer; font-size: 13.5px; }
.etd-reviewer-suggestion:hover { background: var(--etd-bg-alt); }

/* Actions bar */
.etd-actions {
    padding: 18px 28px;
    background: var(--etd-bg-alt);
    border-top: 1px solid var(--etd-rule);
    border-bottom-left-radius: var(--etd-radius-lg);
    border-bottom-right-radius: var(--etd-radius-lg);
    display: flex; gap: 16px; align-items: center; justify-content: space-between; flex-wrap: wrap;
}
.etd-actions-note    { font-size: 12.5px; color: var(--etd-ink-quiet); max-width: 50ch; }
.etd-actions-buttons { display: flex; gap: 10px; align-items: center; }

/* Tag picker - wraps the legacy w3-tag chip output emitted by
   Codifier::build_group_combinations() and Series::build_series().
   Those helpers are also reused by JSActions for on-click toggle
   refreshes, so we override the w3-tag look here rather than
   rewriting both renderers. Result: clickable chips that match the
   v0.2 visual language while keeping the existing AJAX flow intact. */
.etd-tag-picker { display: flex; flex-wrap: wrap; gap: 8px; padding: 4px 0; }
/* Chips corresponding to one of the user's own group combinations get
   a heavier, darker border so their membership is legible even mixed
   in with the rest of the catalogue.  Sits on top of the base +
   selected/unselected styles so an unselected "mine" chip is still an
   outline, just a stronger one; a selected "mine" chip gains the
   darker outer ring on top of the primary fill. */
.etd-tag-picker .w3-tag.etd-tag-mine {
    border-color: var(--etd-ink) !important;
    border-width: 2px !important;
    padding: 5px 11px !important;
}
/* Archived combinations that stay pinned on a doc for historical
   reasons - rendered as a locked chip: dimmed, not clickable, with
   a small padlock glyph.  Their tag is preserved on the doc but
   the user cannot toggle it in the picker. */
.etd-tag-picker .w3-tag.etd-tag-locked {
    cursor: not-allowed;
    opacity: 0.6;
    filter: grayscale(0.35);
}
.etd-tag-picker .w3-tag.etd-tag-locked:hover { opacity: 0.6; }
.etd-tag-picker .w3-tag.etd-tag-locked .etd-tag-locked-mark {
    display: inline-block;
    margin-left: 6px;
    font-size: 11px;
    line-height: 1;
    opacity: 0.75;
}

/* Group-combination chips (Viewable by). Legacy emits each chip as
   <div class="w3-tag w3-padding w3-border ... cursor">. Style is a
   pill that depresses when its w3-opacity-max marker (the
   unselected state) is absent. */
.etd-tag-picker .w3-tag {
    appearance: none;
    display: inline-flex; align-items: center;
    padding: 6px 12px !important;
    border: 1px solid var(--etd-rule-strong) !important;
    border-radius: 999px !important;
    background: var(--etd-surface) !important;
    color: var(--etd-ink) !important;
    font: 600 12.5px/1.3 var(--etd-sans) !important;
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s, box-shadow .12s;
    margin: 0 !important;
    box-shadow: none !important;
}
.etd-tag-picker .w3-tag:hover {
    border-color: var(--etd-primary) !important;
    color: var(--etd-primary-ink) !important;
}
/* Legacy applies w3-opacity-max to unselected chips. Selected chips
   have no opacity class - render them as primary-filled pills. */
.etd-tag-picker .w3-tag:not(.w3-opacity-max) {
    background: var(--etd-primary) !important;
    color: white !important;
    border-color: var(--etd-primary) !important;
}
.etd-tag-picker .w3-tag.w3-opacity-max {
    opacity: 1 !important;
    color: var(--etd-ink-quiet) !important;
    background: var(--etd-surface) !important;
}

/* Series picker (metadata form) - v0.2 tree with click-to-toggle
   selection and click-to-expand branches. Markup is emitted by
   Series::build_series_picker_v2(); the on-click AJAX handlers
   (select_series / select_code_series) return the same markup to
   swap #div_series content, so state is preserved server-side. */
.etd-series-picker {
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    background: var(--etd-surface);
    max-height: 460px;
    overflow-y: auto;
}
.etd-series-picker-tree,
.etd-series-picker-children { display: block; }
.etd-series-picker-node { border-bottom: 1px solid var(--etd-rule); }
.etd-series-picker-node:last-child { border-bottom: 0; }
.etd-series-picker-row {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 14px;
    min-height: 40px;
}
.etd-series-picker-row:hover { background: var(--etd-bg-alt); }
.etd-series-picker-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px;
    border: 0; background: transparent;
    color: var(--etd-ink-quiet);
    cursor: pointer; text-decoration: none;
    flex-shrink: 0;
    border-radius: 4px;
}
.etd-series-picker-toggle:hover { background: var(--etd-primary-soft); color: var(--etd-primary); text-decoration: none; }
.etd-series-picker-branch-open > .etd-series-picker-row .etd-series-chev {
    transform: rotate(45deg);
}
.etd-series-picker-name {
    font: 600 13.5px/1.3 var(--etd-sans);
    color: var(--etd-ink);
    flex: 1; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.etd-series-picker-count {
    font: 600 10.5px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    padding: 3px 7px;
    border-radius: var(--etd-radius-sm);
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    flex-shrink: 0;
}
.etd-series-picker-select {
    appearance: none;
    display: inline-flex; align-items: center; gap: 5px;
    padding: 6px 12px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: 999px;
    background: var(--etd-surface);
    color: var(--etd-ink-quiet);
    font: 600 11.5px/1 var(--etd-sans);
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
    flex-shrink: 0;
}
.etd-series-picker-select:hover {
    border-color: var(--etd-primary);
    color: var(--etd-primary-ink);
}
.etd-series-picker-select-on {
    background: var(--etd-primary);
    color: white;
    border-color: var(--etd-primary);
}
.etd-series-picker-select-on:hover {
    background: var(--etd-primary-hover);
    color: white;
    border-color: var(--etd-primary-hover);
}
/* Nested children - indent + tinted ground to signal hierarchy. */
.etd-series-picker-children {
    background: var(--etd-bg-alt);
    border-top: 1px solid var(--etd-rule);
}
.etd-series-picker-children .etd-series-picker-row { padding-left: 38px; }
.etd-series-picker-children .etd-series-picker-children .etd-series-picker-row { padding-left: 60px; }
.etd-series-picker-children .etd-series-picker-children .etd-series-picker-children .etd-series-picker-row { padding-left: 82px; }

/* Series tree (v0.2 ?a=4 page) - disclosure widgets, no JS needed.
   Branch nodes are <details>; leaves are flat .etd-series-row divs. */
.etd-series-tree { display: flex; flex-direction: column; }
.etd-series-node, .etd-series-row {
    border-bottom: 1px solid var(--etd-rule);
}
.etd-series-tree > :last-child,
.etd-series-tree > :last-child > .etd-series-children > :last-child {
    border-bottom: 0;
}
.etd-series-summary, .etd-series-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px; padding: 14px 22px;
    cursor: pointer;
    list-style: none;
    transition: background .12s;
}
.etd-series-summary::-webkit-details-marker { display: none; }
.etd-series-summary:hover { background: var(--etd-bg-alt); }
.etd-series-row:hover { background: var(--etd-bg-alt); }
.etd-series-row { cursor: default; }
.etd-series-row-main {
    display: inline-flex; align-items: center; gap: 12px;
    min-width: 0; flex: 1;
}
.etd-series-chev {
    width: 10px; height: 10px;
    border-right: 2px solid var(--etd-ink-quiet);
    border-bottom: 2px solid var(--etd-ink-quiet);
    transform: rotate(-45deg);
    transition: transform .15s;
    flex-shrink: 0;
}
.etd-series-node[open] > .etd-series-summary .etd-series-chev {
    transform: rotate(45deg);
}
.etd-series-bullet {
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--etd-ink-faint);
    flex-shrink: 0;
    margin: 0 2px;
}
.etd-series-name-block {
    display: flex; flex-direction: column;
    min-width: 0; flex: 1;
    gap: 4px;
}
.etd-series-name-block > span:first-child {
    display: inline-flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
.etd-series-name {
    font: 600 14.5px/1.3 var(--etd-sans);
    color: var(--etd-ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    min-width: 0;
}
.etd-series-desc {
    font: 400 12.5px/1.45 var(--etd-sans);
    color: var(--etd-ink-quiet);
    max-width: 80ch;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.etd-series-dates {
    font: 500 11px/1 var(--etd-mono);
    color: var(--etd-ink-faint);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    flex-shrink: 0;
}
/* Type chip - coloured by the eight defined values. Each type
   gets its own soft-background + darker-ink pairing so a scan of
   the tree tells you what kind of series each row is at a glance. */
.etd-series-type-chip {
    font: 700 9.5px/1 var(--etd-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 3px 6px;
    border-radius: var(--etd-radius-sm);
    border: 1px solid transparent;
    flex-shrink: 0;
    display: inline-block;
    line-height: 1;
    vertical-align: 2px;
}
.etd-series-type-governance { background: #EEF2FB; color: #1E3FAA; border-color: #C6D0EA; }
.etd-series-type-content    { background: #F1ECFA; color: #5C39A0; border-color: #D5C8ED; }
.etd-series-type-event      { background: #FBF0DF; color: #C0691B; border-color: #EAD3B4; }
.etd-series-type-meeting    { background: #FDF5E7; color: #A0611B; border-color: #F0D9AF; }
.etd-series-type-project    { background: #EAF4F0; color: #1F6E5A; border-color: #BDDCD1; }
.etd-series-type-wp         { background: #F1F5EE; color: #4A6B2E; border-color: #CFDBC0; }
.etd-series-type-topical    { background: #F5EDE1; color: #6B4A2A; border-color: #DFCEB9; }
.etd-series-type-legacy     { background: #F0F0F2; color: #5A6477; border-color: #D6DAE0; }
.etd-series-count {
    font: 600 11px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    letter-spacing: 0.04em;
    padding: 4px 8px;
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-bg-alt);
    flex-shrink: 0;
}
.etd-series-row-actions { display: inline-flex; gap: 8px; flex-shrink: 0; }
.etd-series-meta-btn {
    appearance: none;
    padding: 6px 12px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    color: var(--etd-ink-quiet);
    font: 600 12px/1 var(--etd-sans);
    cursor: pointer;
    transition: border-color .12s, color .12s, background .12s;
    display: inline-flex; align-items: center; gap: 6px;
}
.etd-series-meta-btn:hover {
    border-color: var(--etd-primary);
    color: var(--etd-primary-ink);
    background: var(--etd-primary-soft);
}
/* Nested series - slight inset + tinted ground. */
.etd-series-children {
    background: var(--etd-bg-alt);
    border-top: 1px solid var(--etd-rule);
}
.etd-series-children .etd-series-summary,
.etd-series-children .etd-series-row {
    padding-left: 44px;
}
.etd-series-children .etd-series-children .etd-series-summary,
.etd-series-children .etd-series-children .etd-series-row {
    padding-left: 66px;
}
.etd-series-children .etd-series-children .etd-series-children .etd-series-summary,
.etd-series-children .etd-series-children .etd-series-children .etd-series-row {
    padding-left: 88px;
}

/* Outreach v0.2 wrapper - the legacy renderer's w3-styled table sits
   inside an etd-card. Trim its outer paddings + first-of-type margins
   so it sits flush in the card. */
/* Internal Outreach list (?c=outreach) - rich rows for admin
   audience. Denser than the public card grid: thumbnail on the
   left, code + title + description + tags in the middle, view
   CTA on the right, and the long-form fields (credits, licenses,
   captions) collapse behind a details disclosure per row. */
.etd-outreach-filters {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 20px;
    padding: 16px 18px;
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
}
.etd-outreach-filters .etd-public-search {
    flex: 1 1 300px;
    max-width: none;
    padding: 10px 14px 10px 38px;
    font-size: 14px;
    background-color: var(--etd-surface);
}
.etd-outreach-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.etd-outreach-row {
    display: grid;
    grid-template-columns: 128px 1fr auto;
    gap: 20px;
    padding: 18px 20px;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    transition: border-color .12s, box-shadow .12s;
}
.etd-outreach-row:hover {
    border-color: var(--etd-ink-faint);
    box-shadow: 0 6px 16px rgba(10, 21, 37, .06);
}
.etd-outreach-row-thumb {
    display: block;
    width: 128px; aspect-ratio: 4 / 3;
    background: var(--etd-bg-alt);
    border-radius: var(--etd-radius);
    overflow: hidden;
    border: 1px solid var(--etd-rule);
    align-self: start;
    text-decoration: none !important;
}
.etd-outreach-row-thumb img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
}
.etd-outreach-row-thumb .etd-public-thumb-placeholder {
    width: 100%; height: 100%;
}
.etd-outreach-row-body { min-width: 0; }
.etd-outreach-row-head {
    display: flex; align-items: center;
    gap: 12px; flex-wrap: wrap;
    margin-bottom: 6px;
}
.etd-outreach-row-code {
    font: 700 11.5px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    letter-spacing: 0.06em;
    padding: 4px 8px;
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-sm);
}
.etd-outreach-row-access {
    display: inline-flex; gap: 4px; flex-wrap: wrap;
}
.etd-outreach-access-badge {
    font: 700 10px/1 var(--etd-mono);
    letter-spacing: 0.05em;
    padding: 4px 8px;
    border-radius: var(--etd-radius-sm);
    background: var(--etd-primary-soft);
    color: var(--etd-primary-ink);
    border: 1px solid var(--etd-primary-soft);
}
.etd-outreach-row-title {
    display: block;
    font: 600 16px/1.35 var(--etd-sans);
    color: var(--etd-ink);
    text-decoration: none;
    margin-bottom: 6px;
    text-wrap: balance;
}
.etd-outreach-row-title:hover {
    color: var(--etd-primary);
    text-decoration: none;
}
.etd-outreach-row-desc {
    font-size: 13.5px;
    line-height: 1.5;
    color: var(--etd-ink-quiet);
    margin: 0 0 10px !important;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.etd-outreach-row-tags {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    font-size: 12px;
}
.etd-outreach-row-badges,
.etd-outreach-row-langs {
    display: inline-flex;
    gap: 4px;
    flex-wrap: wrap;
}
.etd-outreach-lang {
    font: 700 10px/1 var(--etd-mono);
    letter-spacing: 0.05em;
    padding: 4px 7px;
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    color: var(--etd-ink-quiet);
    border: 1px dashed var(--etd-rule-strong);
}
.etd-outreach-row-date {
    font: 500 12px/1 var(--etd-mono);
    color: var(--etd-ink-faint);
    font-variant-numeric: tabular-nums;
    margin-left: auto;
}
.etd-outreach-row-cta {
    align-self: start;
    padding: 8px 14px;
    font-size: 13px;
    white-space: nowrap;
}
/* Details disclosure per row for credits/licenses/captions. */
.etd-outreach-details {
    margin-top: 12px;
    border-top: 1px dashed var(--etd-rule);
    padding-top: 12px;
}
.etd-outreach-details-summary {
    list-style: none;
    display: inline-flex; align-items: center; gap: 8px;
    cursor: pointer;
    font: 600 12px/1 var(--etd-sans);
    color: var(--etd-ink-quiet);
    letter-spacing: 0.02em;
    padding: 4px 0;
    user-select: none;
}
.etd-outreach-details-summary::-webkit-details-marker { display: none; }
.etd-outreach-details-summary:hover { color: var(--etd-primary); }
.etd-outreach-details-chev {
    width: 8px; height: 8px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(-45deg);
    transition: transform .15s;
    display: inline-block;
}
.etd-outreach-details[open] .etd-outreach-details-chev {
    transform: rotate(45deg);
}
.etd-outreach-details-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px 24px;
    margin-top: 12px;
    padding: 14px 16px;
    background: var(--etd-bg-alt);
    border-radius: var(--etd-radius);
}
.etd-outreach-details-grid > div .etd-label-up {
    display: block;
    margin-bottom: 6px;
    font-size: 10.5px;
}
.etd-outreach-details-grid > div p {
    font-size: 13px;
    line-height: 1.55;
    color: var(--etd-ink);
    margin: 0;
    word-break: break-word;
}
.etd-outreach-detail-empty {
    color: var(--etd-ink-faint) !important;
    font-style: italic;
}
/* Responsive - stack on narrow viewports. */
@media (max-width: 700px) {
    .etd-outreach-row {
        grid-template-columns: 88px 1fr;
        gap: 14px;
    }
    .etd-outreach-row-thumb { width: 88px; }
    .etd-outreach-row-cta {
        grid-column: 1 / -1;
        justify-self: start;
    }
    .etd-outreach-row-date {
        margin-left: 0;
    }
}

/* Public Outreach - editorial card grid. Public-facing page so
   prioritises imagery + readability. Hero uses the serif display
   face for a magazine feel; cards lead with a thumbnail and clip
   the title to two lines, description to three. Filter chips
   sit under the search on the same row when there's room. */
.etd-public-page {
    max-width: 1240px;
    margin: 0 auto;
    padding: 24px 28px 80px;
}
.etd-public-hero {
    padding: 40px 0 32px;
    border-bottom: 1px solid var(--etd-rule);
    margin-bottom: 32px;
}
.etd-public-display {
    font-family: var(--etd-serif);
    font-size: clamp(36px, 4.4vw, 56px);
    line-height: 1.04;
    letter-spacing: -0.025em;
    font-weight: 600;
    color: var(--etd-ink);
    margin: 10px 0 14px !important;
    max-width: 22ch;
    text-wrap: balance;
}
.etd-public-lede {
    font-size: 17px;
    line-height: 1.55;
    color: var(--etd-ink-quiet);
    max-width: 58ch;
    margin-bottom: 24px !important;
}
.etd-public-filters {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin-top: 20px;
}
.etd-public-search {
    appearance: none;
    flex: 1 1 300px;
    max-width: 460px;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius);
    padding: 12px 16px 12px 40px;
    font: 15px/1.4 var(--etd-sans);
    color: var(--etd-ink);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235A6477' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: 14px 50%;
}
.etd-public-search:focus {
    outline: 0;
    border-color: var(--etd-primary);
    box-shadow: 0 0 0 3px var(--etd-primary-soft);
}
.etd-public-chip-row {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}
.etd-public-chip {
    appearance: none;
    padding: 8px 14px;
    border-radius: 999px;
    border: 1px solid var(--etd-rule-strong);
    background: var(--etd-surface);
    color: var(--etd-ink-quiet);
    font: 600 12.5px/1 var(--etd-sans);
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
    letter-spacing: 0.01em;
}
.etd-public-chip:hover {
    border-color: var(--etd-primary);
    color: var(--etd-primary-ink);
}
.etd-public-chip-active {
    background: var(--etd-ink);
    color: white;
    border-color: var(--etd-ink);
}
.etd-public-chip-active:hover {
    background: var(--etd-ink);
    color: white;
    border-color: var(--etd-ink);
}

.etd-public-meta {
    font: 500 13px/1 var(--etd-sans);
    color: var(--etd-ink-quiet);
    margin-bottom: 20px;
    font-variant-numeric: tabular-nums;
}

.etd-public-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 24px;
}
.etd-public-empty,
.etd-public-empty-live {
    padding: 60px 24px;
    text-align: center;
    color: var(--etd-ink-quiet);
    font-size: 15px;
    line-height: 1.6;
    background: var(--etd-bg-alt);
    border: 1px dashed var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    margin-top: 20px;
}
.etd-public-empty p:first-child,
.etd-public-empty-live p:first-child { color: var(--etd-ink); margin-bottom: 6px !important; }

/* Card */
.etd-public-card {
    display: flex; flex-direction: column;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    overflow: hidden;
    text-decoration: none !important;
    color: inherit;
    transition: transform .18s ease-out, border-color .18s, box-shadow .18s;
    position: relative;
}
.etd-public-card:hover {
    transform: translateY(-2px);
    border-color: var(--etd-ink-faint);
    box-shadow: 0 12px 28px rgba(10, 21, 37, .08);
    text-decoration: none;
}
.etd-public-thumb {
    aspect-ratio: 4 / 3;
    background: var(--etd-bg-alt);
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    border-bottom: 1px solid var(--etd-rule);
}
.etd-public-thumb img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
    transition: transform .3s ease-out;
}
.etd-public-card:hover .etd-public-thumb img { transform: scale(1.03); }
.etd-public-thumb-placeholder {
    width: 100%; height: 100%;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 4px;
    background: linear-gradient(135deg, var(--etd-primary-soft) 0%, var(--etd-bg-alt) 100%);
    position: relative;
    color: var(--etd-primary-ink);
}
.etd-public-thumb-glyph {
    width: 56px; height: 56px;
    background: url("../resources/et-docs-icon.svg") center/contain no-repeat;
}
.etd-public-thumb-glyph::after { content: none; }

/* Outreach type placeholder - shown in .etd-outreach-row-thumb when
   the release has no image thumbnail.  Each type gets its own tinted
   gradient + inline SVG glyph (rendered by
   OutreachMaterialsList::render_type_placeholder_v2) so the material's
   shape reads at a glance without opening the row. */
.etd-om-thumb-icon svg {
    width: 44px; height: 44px;
    display: block;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.etd-om-thumb-label {
    font: 600 10.5px/1 var(--etd-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: inherit;
    opacity: 0.85;
}
.etd-om-thumb-vid { background: linear-gradient(135deg, #EDE1FA 0%, #F6F0FE 100%); color: #5C39A0; }
.etd-om-thumb-aud { background: linear-gradient(135deg, #FDEBD6 0%, #FFF6EA 100%); color: #A5661D; }
.etd-om-thumb-ppt { background: linear-gradient(135deg, #FEE6CF 0%, #FFF3E3 100%); color: #C0691B; }
.etd-om-thumb-pdf { background: linear-gradient(135deg, #FCDCDC 0%, #FDECEC 100%); color: #B94141; }
.etd-om-thumb-xls { background: linear-gradient(135deg, #D9F1E3 0%, #EFFBF3 100%); color: #1F6E5A; }
.etd-om-thumb-doc { background: linear-gradient(135deg, #DEE7F8 0%, #EFF3FB 100%); color: #1E3FAA; }
.etd-om-thumb-zip { background: linear-gradient(135deg, #ECE0CB 0%, #F5EEDE 100%); color: #6B4A2A; }
.etd-om-thumb-img { background: linear-gradient(135deg, #D6ECC8 0%, #EBF6E1 100%); color: #4A6B2E; }
.etd-om-thumb-gen { background: linear-gradient(135deg, var(--etd-primary-soft) 0%, var(--etd-bg-alt) 100%); color: var(--etd-primary-ink); }

/* ─── Outreach materials list (v0.2) ───────────────────────────
   Rebuilt as a card list where each material is a self-contained
   container instead of a dense table row.  Filter panel above
   uses horizontal bands (header, form, chip row) with tinted
   field labels so each control type reads at a glance. */

/* Filter panel */
.etd-om-filters {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    box-shadow: 0 1px 2px rgb(15 23 42 / 0.04);
    overflow: hidden;
    margin-bottom: 16px;
}
.etd-om-filters-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    padding: 14px 18px;
    background: linear-gradient(180deg, var(--etd-primary-soft) 0%, rgba(238,245,251,0.35) 100%);
    border-bottom: 1px solid var(--etd-rule);
}
.etd-om-filters-title {
    display: flex; align-items: center; gap: 12px;
    min-width: 0;
}
.etd-om-filters-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    border-radius: 999px;
    background: var(--etd-surface);
    border: 1px solid #C7D5F4;
    color: var(--etd-primary);
    flex: 0 0 auto;
}
.etd-om-filters-icon i.fa { font-size: 14px; }
.etd-om-filters-title-text {
    display: flex; flex-direction: column;
    line-height: 1.25;
    min-width: 0;
}
.etd-om-filters-heading {
    font: 600 14.5px/1.3 var(--etd-sans);
    color: var(--etd-primary-ink);
    letter-spacing: -0.005em;
}
.etd-om-filters-sub {
    font-size: 12px;
    color: var(--etd-ink-quiet);
    margin-top: 1px;
}
.etd-om-filters-clear {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px;
    border-radius: 999px;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule-strong);
    color: var(--etd-ink-quiet);
    font: 600 12px/1 var(--etd-sans);
    cursor: pointer;
    transition: background .12s, color .12s, border-color .12s;
    flex: 0 0 auto;
}
.etd-om-filters-clear:hover {
    background: var(--etd-bg-alt);
    border-color: var(--etd-ink-faint);
    color: var(--etd-ink);
}
.etd-om-filters-clear i.fa { font-size: 10px; }

/* Form band - grid of labelled controls with breathing room. */
.etd-om-filters-body {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px 18px;
    padding: 16px 18px;
}
@media (min-width: 900px) {
    .etd-om-filters-body { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .etd-om-field-wide { grid-column: span 2; }
}
@media (min-width: 1200px) {
    .etd-om-filters-body { grid-template-columns: repeat(5, minmax(0, 1fr)); }
    .etd-om-field-wide { grid-column: span 2; }
}
.etd-om-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.etd-om-field-label {
    display: inline-flex; align-items: center; gap: 6px;
    font: 600 11px/1 var(--etd-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--etd-ink-quiet);
}
.etd-om-field-label i.fa { font-size: 12px; }
/* Colour accents on each label icon - helps the eye associate a
   field with what it filters without adding chrome elsewhere. */
.etd-om-tint-search  i.fa { color: var(--etd-primary); }
.etd-om-tint-lang    i.fa { color: #1F6E5A; }
.etd-om-tint-access  i.fa { color: #B94141; }
.etd-om-tint-sort    i.fa { color: #5C39A0; }
.etd-om-tint-perpage i.fa { color: #A5661D; }
.etd-om-input,
.etd-om-select {
    width: 100%;
    padding: 9px 12px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    color: var(--etd-ink);
    font: 14px/1.4 var(--etd-sans);
    transition: border-color .12s, box-shadow .12s;
}
.etd-om-input:focus,
.etd-om-select:focus {
    outline: 0;
    border-color: var(--etd-primary);
    box-shadow: 0 0 0 3px var(--etd-primary-soft);
}

/* Chip row - separated by a hairline; each chip carries its own
   filter value. */
.etd-om-filters-chips {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    padding: 12px 18px;
    background: var(--etd-bg-alt);
    border-top: 1px solid var(--etd-rule);
}
.etd-om-filters-chips-label {
    display: inline-flex; align-items: center; gap: 6px;
    font: 600 11px/1 var(--etd-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--etd-ink-quiet);
    margin-right: 4px;
}
.etd-om-filters-chips-label i.fa { color: var(--etd-primary); font-size: 12px; }

/* Card list */
.etd-om-cards {
    display: flex; flex-direction: column;
    gap: 14px;
}
.etd-om-card {
    display: grid;
    grid-template-columns: 168px minmax(0, 1fr);
    gap: 18px;
    padding: 18px 20px;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    box-shadow: 0 1px 2px rgb(15 23 42 / 0.04);
    transition: border-color .12s, box-shadow .16s;
}
.etd-om-card:hover {
    border-color: #C7D5F4;
    box-shadow: 0 4px 14px rgb(15 23 42 / 0.06);
}
@media (max-width: 640px) {
    .etd-om-card { grid-template-columns: 1fr; padding: 14px; gap: 12px; }
}
.etd-om-card-media {
    display: block;
    width: 168px;
    aspect-ratio: 4 / 3;
    border-radius: var(--etd-radius-sm);
    overflow: hidden;
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    align-self: start;
    text-decoration: none !important;
}
@media (max-width: 640px) {
    .etd-om-card-media { width: 100%; max-width: 240px; }
}
.etd-om-card-body {
    display: flex; flex-direction: column;
    gap: 10px;
    min-width: 0;
}
.etd-om-card-head {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: 8px;
    font-size: 12px;
    color: var(--etd-ink-quiet);
}
.etd-om-card-title {
    margin: 0;
    font: 600 17px/1.3 var(--etd-sans);
    letter-spacing: -0.005em;
    color: var(--etd-ink);
    text-wrap: balance;
}
.etd-om-card-title a {
    color: inherit !important;
    text-decoration: none !important;
}
.etd-om-card-title a:hover { color: var(--etd-primary) !important; text-decoration: underline !important; text-underline-offset: 3px; }
.etd-om-card-title a:focus-visible { outline: 2px solid var(--etd-primary); outline-offset: 3px; border-radius: 2px; }
.etd-om-card-date {
    display: inline-flex; align-items: center; gap: 5px;
    color: var(--etd-ink-quiet);
    font-variant-numeric: tabular-nums;
    font-family: var(--etd-mono);
    font-size: 11.5px;
}
.etd-om-card-date i.fa { color: var(--etd-ink-faint); font-size: 11px; }
.etd-om-card-access { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.etd-om-card-metarow {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: 10px;
    margin-top: 2px;
}
.etd-om-card-meta-group { display: inline-flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.etd-om-card-fields {
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px 20px;
    margin: 6px 0 0;
    padding: 10px 0 0;
    border-top: 1px dashed var(--etd-rule);
}
@media (min-width: 900px) {
    .etd-om-card-fields { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.etd-om-card-field { margin: 0; min-width: 0; }
.etd-om-card-field dt {
    font: 600 10.5px/1.3 var(--etd-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--etd-ink-quiet);
    margin-bottom: 2px;
}
.etd-om-card-field dd {
    margin: 0;
    font-size: 13px;
    line-height: 1.5;
    color: var(--etd-ink);
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
}
.etd-om-card-foot {
    display: flex; align-items: center; justify-content: flex-end;
    margin-top: 4px;
}

/* Code chip; access + language chips reused across the card. */
.etd-om-code {
    display: inline-block;
    padding: 3px 9px;
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-sm);
    font: 700 12px/1 var(--etd-mono);
    color: var(--etd-primary-ink);
    letter-spacing: 0.02em;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.etd-om-access {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--etd-primary-soft);
    border: 1px solid #C7D5F4;
    color: var(--etd-primary-ink);
    font: 600 11px/1.3 var(--etd-sans);
    white-space: nowrap;
}
.etd-om-lang {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    color: var(--etd-ink);
    font: 600 11px/1.3 var(--etd-sans);
    letter-spacing: 0.04em;
    white-space: nowrap;
}
.etd-om-muted { color: var(--etd-ink-faint); font-style: italic; }
.etd-om-view {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 16px;
    border-radius: var(--etd-radius-sm);
    background: var(--etd-primary);
    color: #fff !important;
    text-decoration: none !important;
    font: 600 13px/1 var(--etd-sans);
    transition: background .12s, transform .12s;
    white-space: nowrap;
}
.etd-om-view:hover { background: var(--etd-primary-hover); transform: translateY(-1px); }
.etd-om-view:focus-visible { outline: 2px solid var(--etd-primary); outline-offset: 3px; }
.etd-om-view i.fa { font-size: 12px; }

/* Thumbnail image / type placeholder inside the card media slot. */
.etd-om-thumb-img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
}
.etd-om-thumb-cell {
    width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center;
}
.etd-om-thumb-cell svg { width: 48px; height: 48px; display: block; }
.etd-om-thumb-cell.etd-om-thumb-vid { background: linear-gradient(135deg, #EDE1FA 0%, #F6F0FE 100%); color: #5C39A0; }
.etd-om-thumb-cell.etd-om-thumb-aud { background: linear-gradient(135deg, #FDEBD6 0%, #FFF6EA 100%); color: #A5661D; }
.etd-om-thumb-cell.etd-om-thumb-ppt { background: linear-gradient(135deg, #FEE6CF 0%, #FFF3E3 100%); color: #C0691B; }
.etd-om-thumb-cell.etd-om-thumb-pdf { background: linear-gradient(135deg, #FCDCDC 0%, #FDECEC 100%); color: #B94141; }
.etd-om-thumb-cell.etd-om-thumb-xls { background: linear-gradient(135deg, #D9F1E3 0%, #EFFBF3 100%); color: #1F6E5A; }
.etd-om-thumb-cell.etd-om-thumb-doc { background: linear-gradient(135deg, #DEE7F8 0%, #EFF3FB 100%); color: #1E3FAA; }
.etd-om-thumb-cell.etd-om-thumb-zip { background: linear-gradient(135deg, #ECE0CB 0%, #F5EEDE 100%); color: #6B4A2A; }
.etd-om-thumb-cell.etd-om-thumb-img { background: linear-gradient(135deg, #D6ECC8 0%, #EBF6E1 100%); color: #4A6B2E; }
.etd-om-thumb-cell.etd-om-thumb-gen { background: var(--etd-bg-alt); color: var(--etd-ink-quiet); }

/* File-type chips - one per unique extension in the release. */
.etd-om-ftchip {
    display: inline-block;
    padding: 2px 6px;
    margin: 0 3px 2px 0;
    border-radius: var(--etd-radius-sm);
    font: 700 10.5px/1.4 var(--etd-mono);
    letter-spacing: 0.04em;
    border: 1px solid transparent;
    white-space: nowrap;
}
.etd-om-ftchip-vid { background: #EDE1FA; color: #5C39A0; border-color: #DAC8F0; }
.etd-om-ftchip-aud { background: #FDEBD6; color: #A5661D; border-color: #F0D3AA; }
.etd-om-ftchip-ppt { background: #FEE6CF; color: #C0691B; border-color: #F3CFA0; }
.etd-om-ftchip-pdf { background: #FCDCDC; color: #B94141; border-color: #F1BEBE; }
.etd-om-ftchip-xls { background: #D9F1E3; color: #1F6E5A; border-color: #B7DFC7; }
.etd-om-ftchip-doc { background: #DEE7F8; color: #1E3FAA; border-color: #C1D2ED; }
.etd-om-ftchip-zip { background: #ECE0CB; color: #6B4A2A; border-color: #D6C2A0; }
.etd-om-ftchip-img { background: #D6ECC8; color: #4A6B2E; border-color: #B8D8A6; }
.etd-om-ftchip-gen { background: var(--etd-bg-alt); color: var(--etd-ink-quiet); border-color: var(--etd-rule); }

.etd-public-card-body { padding: 18px 20px 14px; flex: 1; }
.etd-public-card-title {
    font: 600 16px/1.35 var(--etd-sans) !important;
    color: var(--etd-ink);
    letter-spacing: -0.005em;
    margin: 0 0 8px !important;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-wrap: balance;
}
.etd-public-card-desc {
    font-size: 13.5px;
    line-height: 1.5;
    color: var(--etd-ink-quiet);
    margin: 0 !important;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.etd-public-card-foot {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px;
    padding: 12px 20px 16px;
    border-top: 1px solid var(--etd-rule);
    background: var(--etd-bg-alt);
    min-height: 44px;
}
.etd-public-card-badges { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.etd-public-badge {
    font: 700 10px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    padding: 4px 7px;
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    letter-spacing: 0.04em;
}
.etd-public-badge-pdf   { color: #A83232; border-color: #E8C4C4; background: #FCEDED; }
.etd-public-badge-jpg,
.etd-public-badge-jpeg,
.etd-public-badge-png,
.etd-public-badge-gif,
.etd-public-badge-webp  { color: #5C39A0; border-color: #D5C8ED; background: #F1ECFA; }
.etd-public-badge-mp4,
.etd-public-badge-mov,
.etd-public-badge-avi   { color: #1F6E5A; border-color: #BDDCD1; background: #EAF4F0; }
.etd-public-badge-ppt,
.etd-public-badge-pptx  { color: #C0691B; border-color: #EAD3B4; background: #FBF0DF; }
.etd-public-badge-doc,
.etd-public-badge-docx  { color: #1E3FAA; border-color: #C6D0EA; background: #EEF2FB; }
.etd-public-badge-zip,
.etd-public-badge-rar   { color: #6B4A2A; border-color: #DFCEB9; background: #F5EDE1; }
.etd-public-card-date {
    font: 500 12px/1 var(--etd-mono);
    color: var(--etd-ink-faint);
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}

/* Pagination */
.etd-public-pagination {
    display: flex; align-items: center; justify-content: center;
    gap: 8px; margin-top: 40px;
    flex-wrap: wrap;
}
.etd-public-page-btn {
    padding: 8px 14px;
    border-radius: var(--etd-radius);
    border: 1px solid var(--etd-rule-strong);
    background: var(--etd-surface);
    color: var(--etd-ink);
    font: 600 13px/1 var(--etd-sans);
    text-decoration: none !important;
    transition: border-color .12s, color .12s;
}
.etd-public-page-btn:hover:not(.etd-public-page-btn-disabled) {
    border-color: var(--etd-primary);
    color: var(--etd-primary-ink);
}
.etd-public-page-btn-disabled {
    color: var(--etd-ink-faint);
    cursor: not-allowed;
}
.etd-public-page-numbers { display: inline-flex; gap: 4px; align-items: center; }
.etd-public-page-num {
    min-width: 34px; padding: 8px 10px;
    border-radius: var(--etd-radius-sm);
    color: var(--etd-ink-quiet);
    font: 600 13px/1 var(--etd-mono);
    text-align: center;
    text-decoration: none !important;
    font-variant-numeric: tabular-nums;
    transition: background .12s, color .12s;
}
.etd-public-page-num:hover { background: var(--etd-bg-alt); color: var(--etd-ink); }
.etd-public-page-num-current {
    background: var(--etd-ink);
    color: white !important;
}
.etd-public-page-ellipsis {
    color: var(--etd-ink-faint);
    padding: 8px 4px;
    font-family: var(--etd-mono);
}

/* Public nav - the shared topbar renders with a "Public access" badge
   for unauthenticated views. Trim padding on this public page since
   we set our own container width and rhythm. */
body:has(.etd-public-page) .etd-topbar { border-bottom: 1px solid var(--etd-rule); }

/* Stats page - horizontal bar rows for by-type / by-year sections.
   Track + fill uses primary blue; labels align to a fixed column so
   bars start at the same x for scanning. */
.etd-stat-strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
}
.etd-stats-empty {
    padding: 28px 22px;
    text-align: center;
    color: var(--etd-ink-quiet);
    font-size: 14px;
}
.etd-stats-bar-row {
    display: grid;
    grid-template-columns: 180px 1fr 80px;
    align-items: center;
    gap: 14px;
    padding: 12px 22px;
    border-bottom: 1px solid var(--etd-rule);
}
.etd-stats-bar-row:last-child { border-bottom: 0; }
.etd-stats-bar-lbl {
    font: 600 13px/1.3 var(--etd-sans);
    color: var(--etd-ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.etd-stats-bar-track {
    display: block; position: relative;
    height: 8px;
    background: var(--etd-bg-alt);
    border-radius: 999px;
    overflow: hidden;
}
.etd-stats-bar-fill {
    display: block; height: 100%;
    background: linear-gradient(90deg, var(--etd-primary), var(--etd-primary-hover));
    border-radius: 999px;
    transition: width .4s ease-out;
}
.etd-stats-bar-num {
    font: 700 14px/1 var(--etd-mono);
    color: var(--etd-ink);
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Review action buttons on the Reviews dashboard rows. Primary
   action (usually Approve / Open / Start) uses the primary blue;
   secondary actions (Request changes / Reject) are ghost pills. */
.etd-review-actions {
    display: inline-flex;
    gap: 6px;
    flex-wrap: wrap;
    align-items: center;
}
.etd-review-action {
    appearance: none;
    padding: 5px 10px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    color: var(--etd-ink-quiet);
    font: 600 11.5px/1 var(--etd-sans);
    cursor: pointer;
    transition: border-color .12s, color .12s, background .12s;
}
.etd-review-action:hover {
    border-color: var(--etd-primary);
    color: var(--etd-primary);
}
.etd-review-action-primary {
    background: var(--etd-primary);
    color: white;
    border-color: var(--etd-primary);
}
.etd-review-action-primary:hover {
    background: var(--etd-primary-hover);
    border-color: var(--etd-primary-hover);
    color: white;
}
.etd-review-action:disabled {
    opacity: 0.5;
    cursor: wait;
}
.etd-review-action-danger {
    color: var(--etd-crit);
    border-color: #ECC0BE;
}
.etd-review-action-danger:hover {
    background: var(--etd-crit-soft);
    border-color: var(--etd-crit);
    color: var(--etd-crit);
}
/* Row layout accommodates the new Actions column. */
.etd-row-reviews {
    grid-template-columns: 100px minmax(0, 1.4fr) 88px 128px 120px minmax(200px, auto);
}

/* v0.2 Search page - two-column layout: form on the left, live
   results pane on the right. Stacks on narrow viewports. */
.etd-search-layout {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    gap: 20px;
    align-items: start;
}
@media (max-width: 900px) {
    .etd-search-layout { grid-template-columns: 1fr; }
}
.etd-search-form { margin: 0 !important; }
.etd-search-results {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    padding: 18px 20px;
    max-height: calc(100vh - 200px);
    overflow-y: auto;
    position: sticky;
    top: 84px;
}
.etd-search-results-head {
    display: flex; align-items: baseline; justify-content: space-between;
    margin-bottom: 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--etd-rule);
}
.etd-search-results-count {
    font: 600 12px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    font-variant-numeric: tabular-nums;
}
.etd-search-results-body {
    display: flex; flex-direction: column;
    gap: 6px;
}
.etd-search-results-idle {
    color: var(--etd-ink-quiet);
    font-size: 13px;
    line-height: 1.55;
    margin: 8px 0 !important;
}
.etd-search-result {
    display: flex; flex-direction: column;
    gap: 4px;
    padding: 10px 12px;
    border-radius: var(--etd-radius);
    border: 1px solid transparent;
    background: var(--etd-surface);
    text-decoration: none !important;
    transition: background .12s, border-color .12s;
}
.etd-search-result:hover {
    background: var(--etd-bg-alt);
    border-color: var(--etd-rule);
}
.etd-search-result-code {
    font: 700 10.5px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    letter-spacing: 0.04em;
}
.etd-search-result-title {
    font: 600 13.5px/1.35 var(--etd-sans);
    color: var(--etd-ink);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.etd-search-result-meta {
    display: flex; gap: 8px;
    font-size: 11.5px;
    color: var(--etd-ink-quiet);
    align-items: baseline;
    flex-wrap: wrap;
}
.etd-search-result-authors {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    max-width: 100%;
    min-width: 0;
    font-style: italic;
}

/* Series popular-tags cloud - sits above the hierarchical tree
   on the Series page. Pills sized by usage in four quantised
   buckets so the cloud has visual rhythm; alphabetical for
   browsable scanning. */
.etd-series-cloud {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    padding: 22px 24px;
    margin-bottom: 24px;
}
.etd-series-cloud-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
    margin-bottom: 16px;
}
.etd-series-cloud-note {
    font: 500 12px/1 var(--etd-sans);
    color: var(--etd-ink-faint);
    letter-spacing: 0.01em;
}
.etd-series-cloud-list {
    display: flex; flex-wrap: wrap;
    gap: 10px 12px;
    align-items: baseline;
}
.etd-series-cloud-tag {
    display: inline-flex; align-items: baseline; gap: 6px;
    padding: 6px 12px;
    border-radius: 999px;
    background: var(--etd-primary-soft);
    color: var(--etd-primary-ink);
    border: 1px solid var(--etd-primary-soft);
    text-decoration: none !important;
    line-height: 1.2;
    transition: background .12s, border-color .12s, transform .12s;
}
.etd-series-cloud-tag:hover {
    background: var(--etd-primary);
    border-color: var(--etd-primary);
    color: white !important;
    transform: translateY(-1px);
}
.etd-series-cloud-tag:hover .etd-series-cloud-count { color: rgba(255,255,255,0.85); }
.etd-series-cloud-count {
    font: 700 10.5px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.03em;
}
/* Four size buckets - smallest (0) up to largest (3). Font-weight
   also stepped so the cloud reads with hierarchy. */
.etd-series-cloud-tag-0 { font-size: 12px;    font-weight: 500; }
.etd-series-cloud-tag-1 { font-size: 13.5px;  font-weight: 600; }
.etd-series-cloud-tag-2 { font-size: 15px;    font-weight: 600; padding: 7px 14px; }
.etd-series-cloud-tag-3 { font-size: 17px;    font-weight: 700; padding: 8px 16px; }

/* Custom v0.2 file-type icons. Each carries a distinct colour so
   PDFs / images / video / spreadsheets scan differently in a
   file list. Icon markup is a page shape + a type-specific glyph
   (Files::render_file_icon_v2). */
.etd-ficon {
    display: inline-block;
    vertical-align: -3px;
    margin-right: 4px;
}
.etd-ficon-pdf  { color: #B94141; }
.etd-ficon-doc  { color: #1E3FAA; }
.etd-ficon-txt  { color: #4A5567; }
.etd-ficon-xls  { color: #1F6E5A; }
.etd-ficon-ppt  { color: #C0691B; }
.etd-ficon-img  { color: #5C39A0; }
.etd-ficon-vid  { color: #2E7B8A; }
.etd-ficon-aud  { color: #A5661D; }
.etd-ficon-zip  { color: #6B4A2A; }
.etd-ficon-code { color: #4A6B2E; }
.etd-ficon-gen  { color: var(--etd-ink-quiet); }

/* Doc-type pill on codifier rows - small coloured chip that
   makes scanning by type faster than plain text. Ten palette
   slots (indexed by doc_type_id mod 10 + 1) - soft background,
   darker ink for readability. */
.etd-doctype {
    display: inline-block;
    padding: 3px 8px;
    border-radius: var(--etd-radius-sm);
    font: 600 11px/1.3 var(--etd-sans);
    letter-spacing: 0.01em;
    border: 1px solid transparent;
    max-width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    vertical-align: middle;
}
.etd-doctype-1  { background: #EEF2FB; color: #1E3FAA; border-color: #C6D0EA; } /* blue */
.etd-doctype-2  { background: #FBF0DF; color: #A0611B; border-color: #EAD3B4; } /* amber */
.etd-doctype-3  { background: #EAF4F0; color: #1F6E5A; border-color: #BDDCD1; } /* teal */
.etd-doctype-4  { background: #F1ECFA; color: #5C39A0; border-color: #D5C8ED; } /* violet */
.etd-doctype-5  { background: #FCEDED; color: #A83232; border-color: #E8C4C4; } /* red */
.etd-doctype-6  { background: #E7F1F5; color: #2E7B8A; border-color: #C0DDE5; } /* slate teal */
.etd-doctype-7  { background: #F5EDE1; color: #6B4A2A; border-color: #DFCEB9; } /* umber */
.etd-doctype-8  { background: #F1F5EE; color: #4A6B2E; border-color: #CFDBC0; } /* olive */
.etd-doctype-9  { background: #F0F0F2; color: #5A6477; border-color: #D6DAE0; } /* slate */
.etd-doctype-10 { background: #FDF5E7; color: #C0691B; border-color: #F0D9AF; } /* warm amber */

/* Two-column chart row. Stacks on narrow viewports. */
.etd-stats-charts {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 20px;
    margin-bottom: 24px;
}
@media (max-width: 900px) {
    .etd-stats-charts { grid-template-columns: 1fr; }
}
.etd-stats-chart-card { display: flex; flex-direction: column; }
.etd-stats-chart-body {
    padding: 20px 22px 24px;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Donut chart - ring + centered total + legend to the right. */
.etd-stats-donut-wrap {
    display: flex; align-items: center; gap: 24px;
    width: 100%;
}
.etd-stats-donut { flex-shrink: 0; }
.etd-stats-donut svg { display: block; }
.etd-stats-donut-total {
    font: 700 26px/1 var(--etd-mono);
    fill: var(--etd-ink);
    font-variant-numeric: tabular-nums;
}
.etd-stats-donut-lbl {
    font: 500 11px/1 var(--etd-sans);
    fill: var(--etd-ink-quiet);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.etd-stats-legend {
    flex: 1;
    display: flex; flex-direction: column;
    gap: 6px;
    min-width: 0;
}
.etd-stats-legend-row {
    display: grid;
    grid-template-columns: 12px 1fr auto auto;
    gap: 10px;
    align-items: center;
    font-size: 12.5px;
    line-height: 1.3;
}
.etd-stats-legend-swatch {
    width: 10px; height: 10px;
    border-radius: 2px;
    display: inline-block;
}
.etd-stats-legend-lbl {
    color: var(--etd-ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    min-width: 0;
}
.etd-stats-legend-num {
    font: 600 12px/1 var(--etd-mono);
    color: var(--etd-ink);
    font-variant-numeric: tabular-nums;
}
.etd-stats-legend-pct {
    font: 500 11px/1 var(--etd-mono);
    color: var(--etd-ink-quiet);
    min-width: 3ch;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Area chart - polyline + filled area + data points + labels. */
.etd-stats-area { display: block; overflow: visible; }
.etd-stats-axis-lbl {
    font: 500 10.5px/1 var(--etd-mono);
    fill: var(--etd-ink-quiet);
    letter-spacing: 0.02em;
}
.etd-stats-value-lbl {
    font: 700 10.5px/1 var(--etd-mono);
    fill: var(--etd-ink);
    font-variant-numeric: tabular-nums;
}

/* Sign-in page - shown to every unauthenticated visitor. Centered
   card on a cool-blue ground; the wordmark glyph reads as an
   institutional mark in the header slot. */
.etd-signin-page {
    min-height: 100vh;
    display: flex; align-items: center; justify-content: center;
    padding: 40px 24px;
    background: var(--etd-ground);
}
.etd-signin-card {
    width: 100%; max-width: 460px;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-lg);
    box-shadow: var(--etd-shadow-2);
    padding: 44px 40px;
    display: flex; flex-direction: column; gap: 14px;
    text-align: left;
}
.etd-signin-glyph {
    width: 48px; height: 48px;
    background: url("../resources/et-docs-icon.svg") center/contain no-repeat;
    margin-bottom: 6px;
}
.etd-signin-glyph::after { content: none; }
.etd-signin-title {
    font-family: var(--etd-serif);
    font-size: 30px; line-height: 1.1;
    letter-spacing: -0.02em;
    margin: 0 !important;
    color: var(--etd-ink);
}
.etd-signin-lede {
    font-size: 15px; line-height: 1.55;
    color: var(--etd-ink-quiet);
    max-width: 38ch;
}
.etd-signin-form { display: flex; flex-direction: column; gap: 16px; margin-top: 8px; }
.etd-signin-form .etd-field {
    padding: 0;
    border: 0;
    gap: 6px;
}
.etd-signin-form .etd-field-label {
    font: 600 12px/1.2 var(--etd-sans);
    color: var(--etd-ink-quiet);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
.etd-signin-cta {
    align-self: flex-start;
    margin-top: 8px;
    padding: 12px 20px;
    font-size: 15px;
}
.etd-signin-help {
    font-size: 12.5px;
    color: var(--etd-ink-faint);
    margin-top: 6px !important;
}

/* Modal - modernised to match etmd-next's modal aesthetic
   (larger radius, softer/blurred backdrop, more restrained shadow,
   neutral head by default rather than warning-tinted).  Ports
   every existing .etd-modal instance across the app in one shot -
   no per-modal markup changes.  The neutral / warn / error header
   variants below stay wired to the same class names so existing
   markup keeps opting into the right accent colour. */
.etd-modal {
    position: fixed; inset: 0;
    background: rgb(15 23 42 / 0.45);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    display: none;
    align-items: center; justify-content: center;
    padding: 24px; z-index: 1000;
}
.etd-modal[data-open="true"] {
    display: flex;
    animation: etd-modal-in 140ms ease-out;
}
@keyframes etd-modal-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.etd-modal-content {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: 14px;
    box-shadow: 0 20px 45px rgb(15 23 42 / 0.18);
    width: min(560px, calc(100vw - 2rem));
    max-height: calc(100vh - 3rem);
    overflow: hidden;
    display: grid;
    grid-template-rows: auto 1fr auto;
    animation: etd-modal-card-in 160ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes etd-modal-card-in {
    from { transform: translateY(6px) scale(0.985); opacity: 0; }
    to   { transform: translateY(0)   scale(1);      opacity: 1; }
}
/* Head - neutral by default, no warning tint.  The plain / error
   variants below opt in per-modal for context-appropriate accent
   colours. */
.etd-modal-head {
    padding: 18px 24px;
    border-bottom: 1px solid var(--etd-rule);
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--etd-surface);
}
.etd-modal-head h3 { color: var(--etd-ink); margin: 0; font-size: 16px; font-weight: 600; }
/* Neutral / accent-tinted header - used by modals that collect
   input rather than confirm a destructive-or-caution action
   (e.g. the Request-changes modal). */
.etd-modal-head.etd-modal-head-plain { background: var(--etd-primary-soft); }
.etd-modal-head.etd-modal-head-plain h3 { color: var(--etd-primary-ink); }
/* Warning-tinted header - used by confirm-delete / cautionary
   dialogs.  Previously the default; now opt-in. */
.etd-modal-head.etd-modal-head-warn { background: var(--etd-warn-soft); }
.etd-modal-head.etd-modal-head-warn h3 { color: var(--etd-ink); }
/* Error header - global error modal + destructive-outcome
   dialogs.  Soft-red background, critical-tinted heading. */
.etd-modal-head.etd-modal-head-error { background: var(--etd-crit-soft); }
.etd-modal-head.etd-modal-head-error h3 { color: var(--etd-crit); }
.etd-modal-head.etd-modal-head-error::before {
    content: '⚠';
    font-size: 18px;
    color: var(--etd-crit);
    margin-right: 4px;
}
.etd-modal-body { padding: 20px 24px; color: var(--etd-ink); overflow-y: auto; }
.etd-modal-body p + p { margin-top: 10px; }
.etd-modal-foot {
    padding: 14px 24px;
    background: var(--etd-bg-alt);
    border-top: 1px solid var(--etd-rule);
    display: flex; gap: 10px; justify-content: flex-end;
}

/* Upload drawer (v0.2) - sits inside the shared w3-sidenav shell
   but uses etd-* markup throughout the body. The .etd-drawer /
   .etd-drawer-head / .etd-drawer-body scoping keeps the reskin
   overrides in the section below from double-styling this one. */
.etd-drawer.etd-drawer-upload {
    background: var(--etd-surface) !important;
}
.etd-drawer-head {
    padding: 20px 22px 14px !important;
    background: var(--etd-surface) !important;
    border-bottom: 1px solid var(--etd-rule) !important;
    position: sticky; top: 0; z-index: 1;
}
.etd-drawer-head h2 {
    font: 600 17px/1.3 var(--etd-sans) !important;
    color: var(--etd-ink) !important;
    margin: 0 !important;
    letter-spacing: -0.005em !important;
    display: flex; align-items: center; gap: 10px;
}
.etd-drawer-head h2 i.fa { color: var(--etd-primary); font-size: 15px; }
.etd-drawer-close {
    position: absolute; top: 14px; right: 14px;
    width: 30px; height: 30px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: transparent !important;
    color: var(--etd-ink-quiet) !important;
    font-size: 22px !important;
    line-height: 1 !important;
    cursor: pointer;
    transition: background .12s, color .12s;
}
.etd-drawer-close:hover {
    background: var(--etd-bg-alt) !important;
    color: var(--etd-ink) !important;
}
.etd-drawer-body {
    padding: 22px !important;
    display: flex; flex-direction: column; gap: 20px;
}

/* ─── Series metadata drawer (v0.2) ─────────────────────────────
   Wraps the etd-drawer body when Series::build_series_metadata_bar
   emits the metadata pane. Two modes render inside .etd-meta-drawer:
   a read-only view (breadcrumb ribbon → heading → dl of fields →
   action buttons → collapsible history) and an edit form (heading →
   fields → admin picker → save/cancel).  All markup is pure v0.2 -
   the shared w3-sidenav reskin above still normalises the outer
   chrome.  */
/* Every direct child of the drawer body - breadcrumb, heading,
   list, actions, history - starts at the same left edge.  The
   drawer body's 22px padding is the only inset that matters; nothing
   inside adds its own outer padding.  Gaps between blocks are kept
   deliberately tight so the drawer reads as one grouped surface
   rather than a stack of boxes. */
.etd-meta-drawer { display: block !important; }
.etd-meta-drawer > * { margin: 0; }
.etd-meta-drawer > * + * { margin-top: 12px; }
.etd-meta-drawer > .etd-meta-list + .etd-meta-actions,
.etd-meta-drawer > .etd-meta-actions + .etd-meta-history { margin-top: 16px; }

/* Breadcrumb - a quiet single line above the heading, no box.
   The path contains its own <a> and
   <i class="fa fa-arrow-circle-right">; we tone those down so the
   whole line reads as navigation, not a set of buttons. */
.etd-meta-path {
    display: flex; align-items: flex-start; gap: 8px;
    padding: 0;
    background: transparent;
    border: 0;
    color: var(--etd-ink-quiet);
    font-size: 12.5px;
    line-height: 1.45;
}
.etd-meta-path > i.fa {
    color: var(--etd-primary);
    margin-top: 2px;
    flex: 0 0 auto;
}
.etd-meta-path-text { color: var(--etd-ink-quiet); word-break: break-word; }
.etd-meta-path-text a {
    color: var(--etd-primary) !important;
    text-decoration: none;
}
.etd-meta-path-text a:hover { text-decoration: underline; }
.etd-meta-path-text i.fa {
    color: var(--etd-ink-faint);
    font-size: 10px;
    margin: 0 2px;
}

/* Heading - series name, no chips (Type / Dates now live in the
   metadata list where they carry their own explanatory hint). */
.etd-meta-heading {
    display: flex; flex-direction: column; gap: 6px;
}
.etd-meta-title {
    margin: 0;
    font: 600 20px/1.25 var(--etd-sans);
    letter-spacing: -0.01em;
    color: var(--etd-ink);
    text-wrap: balance;
}

/* Metadata list - label, hint, and value all stack, so every row
   reads as a single column that aligns to the drawer's left edge.
   Rows are separated by a hairline rule instead of a box border so
   the whole list feels like part of the drawer, not a nested
   container. */
.etd-meta-list {
    display: flex; flex-direction: column;
    margin: 0;
    border: 0;
    border-top: 1px solid var(--etd-rule);
    background: transparent;
}
.etd-meta-row {
    display: block;
    padding: 10px 0;
    border-bottom: 1px solid var(--etd-rule);
}
.etd-meta-row:last-child { border-bottom: 0; }
.etd-meta-label {
    margin: 0 0 2px;
    font: 600 11px/1.3 var(--etd-sans);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--etd-ink-quiet);
}
.etd-meta-hint {
    margin: 0 0 6px;
    font-size: 12px;
    line-height: 1.4;
    color: var(--etd-ink-faint);
}
.etd-meta-value {
    margin: 0;
    color: var(--etd-ink);
    font-size: 14px;
    line-height: 1.5;
    word-break: break-word;
}
.etd-meta-value a { color: var(--etd-primary) !important; }
.etd-meta-value a:hover { text-decoration: underline; }
.etd-meta-link-mono {
    font-family: var(--etd-mono);
    font-size: 12.5px;
    word-break: break-all;
}
.etd-meta-datestamp {
    display: inline-flex; align-items: center; gap: 6px;
    color: var(--etd-ink);
    font-variant-numeric: tabular-nums;
}
.etd-meta-datestamp i.fa {
    color: var(--etd-ink-faint);
    font-size: 12px;
    margin: 0;
}
.etd-meta-chip-row {
    display: flex; flex-wrap: wrap; gap: 6px;
}

/* Admin chips inside the view-mode Administrators row. */
.etd-admin-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--etd-primary-soft);
    border: 1px solid #C7D5F4;
    color: var(--etd-primary-ink);
    font: 600 11.5px/1.3 var(--etd-sans);
}
.etd-admin-chip i.fa {
    color: var(--etd-primary);
    font-size: 10px;
    margin: 0;
}

/* Action button row (both view and edit modes). */
.etd-meta-actions {
    display: flex; flex-wrap: wrap; gap: 8px;
    justify-content: flex-end;
}
.etd-meta-actions .btn-primary,
.etd-meta-actions .btn-quiet,
.etd-meta-actions .etd-btn-danger {
    font-size: 13px;
    padding: 8px 14px;
}
/* Danger button - matches the shape of .btn-quiet but tinted for
   destructive actions (Archive).  Kept subtle so it doesn't fight
   the primary action for attention. */
.etd-btn-danger {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 14px;
    border-radius: var(--etd-radius);
    background: var(--etd-surface);
    border: 1px solid #ECC0BE;
    color: var(--etd-crit);
    font: 600 13px/1 var(--etd-sans);
    cursor: pointer;
    text-decoration: none !important;
    transition: background .12s, border-color .12s, color .12s;
}
.etd-btn-danger:hover {
    background: var(--etd-crit-soft);
    border-color: var(--etd-crit);
    color: var(--etd-crit);
}
.etd-btn-danger:focus-visible { outline: 2px solid var(--etd-crit); outline-offset: 2px; }
.etd-btn-danger i.fa { color: inherit; font-size: 12px; }

/* Collapsible change history. */
.etd-meta-history {
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    background: var(--etd-bg-alt);
}
.etd-meta-history > summary {
    padding: 10px 14px;
    font: 600 12.5px/1 var(--etd-sans);
    color: var(--etd-ink-quiet);
    cursor: pointer;
    list-style: none;
    display: flex; align-items: center; gap: 8px;
}
.etd-meta-history > summary::-webkit-details-marker { display: none; }
.etd-meta-history > summary::after {
    content: '▸';
    margin-left: auto;
    color: var(--etd-ink-faint);
    transition: transform .12s;
}
.etd-meta-history[open] > summary::after { transform: rotate(90deg); }
.etd-meta-history > summary i.fa { color: var(--etd-ink-faint); margin: 0; }
.etd-meta-history-body {
    padding: 12px 14px;
    background: var(--etd-surface);
    border-top: 1px solid var(--etd-rule);
    font-size: 12.5px;
    color: var(--etd-ink-quiet);
    line-height: 1.5;
}

/* Edit form structure.  Overrides the generic .etd-field styling
   defined higher up (24px+28px padding + border-bottom): inside a
   Series-metadata drawer we want fields flush with the drawer's own
   left edge and separated only by the form's own gap. */
.etd-meta-form {
    display: flex; flex-direction: column; gap: 14px;
    margin: 0;
}
.etd-meta-form .etd-field {
    display: flex; flex-direction: column; gap: 4px;
    padding: 0;
    border: 0;
}
.etd-meta-form .etd-field-label {
    font-weight: 600;
    font-size: 13.5px;
    color: var(--etd-ink);
}
.etd-meta-form .etd-field-hint {
    margin: 0 0 4px;
    font-size: 12px;
    line-height: 1.4;
    color: var(--etd-ink-faint);
    max-width: none;
}
.etd-meta-form .etd-field-sublabel {
    margin: 0;
    font-size: 12px;
    color: var(--etd-ink-quiet);
    font-weight: 500;
}
.etd-meta-form .etd-field-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin-top: 2px;
}
@media (max-width: 480px) {
    .etd-meta-form .etd-field-row { grid-template-columns: 1fr; }
}
.etd-meta-form textarea.etd-input {
    resize: vertical;
    min-height: 60px;
    font-family: var(--etd-sans);
}

/* Filter input above the admin picker. */
.etd-admin-filter {
    position: relative;
    display: flex;
    margin-bottom: 8px;
}
.etd-admin-filter > i.fa {
    position: absolute;
    left: 10px; top: 50%;
    transform: translateY(-50%);
    color: var(--etd-ink-faint);
    font-size: 12px;
    pointer-events: none;
}
.etd-admin-filter-input {
    width: 100%;
    padding: 8px 10px 8px 30px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    color: var(--etd-ink);
    font: 13px/1.4 var(--etd-sans);
    transition: border-color .12s, box-shadow .12s;
}
.etd-admin-filter-input:focus {
    outline: 0;
    border-color: var(--etd-primary);
    box-shadow: 0 0 0 3px var(--etd-primary-soft);
}

/* Series-administrators picker - scrollable, per-user rows with a
   pill toggle on the right that swaps colour when selected.  Kept
   as a plain button so keyboard/AT users can toggle it; the JS
   select_series_admin round-trip still re-renders on change. */
.etd-admin-picker {
    max-height: 260px;
    overflow-y: auto;
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    background: var(--etd-surface);
}
.etd-admin-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--etd-rule);
}
.etd-admin-row:last-child { border-bottom: 0; }
.etd-admin-name {
    display: flex; flex-direction: column; gap: 1px;
    color: var(--etd-ink);
    line-height: 1.3;
    min-width: 0;
    word-break: break-word;
}
.etd-admin-primary { font-size: 13.5px; font-weight: 500; }
.etd-admin-primary .etd-admin-ru {
    font-weight: 400;
    color: var(--etd-ink-quiet);
    font-size: 12.5px;
}
.etd-admin-sub {
    font-family: var(--etd-mono);
    font-size: 11.5px;
    color: var(--etd-ink-quiet);
}
.etd-admin-empty {
    padding: 12px 14px;
    color: var(--etd-ink-quiet);
    font-size: 13px;
    text-align: center;
}
.etd-admin-chip .etd-admin-chip-ru {
    font-weight: 400;
    color: var(--etd-primary-ink);
    opacity: 0.75;
    font-size: 11px;
}
.etd-admin-toggle {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule-strong);
    color: var(--etd-ink-quiet);
    font: 600 11.5px/1.3 var(--etd-sans);
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
    flex: 0 0 auto;
}
.etd-admin-toggle:hover {
    background: var(--etd-bg-alt);
    border-color: var(--etd-ink-faint);
    color: var(--etd-ink);
}
.etd-admin-toggle i.fa { font-size: 10px; margin: 0; color: inherit; }
.etd-admin-toggle-on {
    background: var(--etd-primary-soft);
    border-color: #C7D5F4;
    color: var(--etd-primary-ink);
}
.etd-admin-toggle-on:hover {
    background: var(--etd-primary-soft);
    border-color: var(--etd-primary);
    color: var(--etd-primary-ink);
}

/* Upload form */
.etd-upload-form { display: flex; flex-direction: column; gap: 20px; margin: 0; }
.etd-upload-field { display: flex; flex-direction: column; gap: 8px; }
.etd-upload-field .etd-label-up { display: block; }

/* Segmented main / annex radio group */
.etd-upload-segment {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}
.etd-upload-seg-opt {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius);
    cursor: pointer;
    background: var(--etd-surface);
    transition: border-color .12s, background .12s;
}
.etd-upload-seg-opt:hover { border-color: var(--etd-ink-faint); }
.etd-upload-seg-opt:has(input:checked) {
    border-color: var(--etd-primary);
    background: var(--etd-primary-soft);
}
.etd-upload-seg-opt input {
    accent-color: var(--etd-primary);
    margin: 3px 0 0;
    flex-shrink: 0;
}
.etd-upload-seg-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.etd-upload-seg-title {
    font: 600 13.5px/1.25 var(--etd-sans);
    color: var(--etd-ink);
}
.etd-upload-seg-hint {
    font: 400 12px/1.4 var(--etd-sans);
    color: var(--etd-ink-quiet);
}

/* Drop-zone-styled file input */
.etd-upload-drop {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 20px 18px;
    border: 2px dashed var(--etd-rule-strong);
    border-radius: var(--etd-radius);
    background: var(--etd-bg-alt);
    cursor: pointer;
    transition: border-color .12s, background .12s;
    position: relative;
}
.etd-upload-drop:hover {
    border-color: var(--etd-primary);
    background: var(--etd-primary-soft);
}
.etd-upload-drop.etd-upload-drop-has-file {
    border-style: solid;
    border-color: var(--etd-primary);
    background: var(--etd-primary-soft);
}
.etd-upload-input {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
    width: 100%; height: 100%;
}
.etd-upload-drop-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px;
    border-radius: 50%;
    background: var(--etd-primary-soft);
    color: var(--etd-primary);
    flex-shrink: 0;
}
.etd-upload-drop-icon i.fa { font-size: 18px; }
.etd-upload-drop-has-file .etd-upload-drop-icon {
    background: var(--etd-primary);
    color: white;
}
.etd-upload-drop-body {
    display: flex; flex-direction: column; gap: 3px;
    min-width: 0; flex: 1;
}
.etd-upload-drop-name {
    font: 600 13.5px/1.3 var(--etd-sans);
    color: var(--etd-ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    max-width: 100%;
}
.etd-upload-drop-hint {
    font: 400 12px/1.3 var(--etd-sans);
    color: var(--etd-ink-quiet);
}

/* Actions row + progress */
.etd-upload-actions {
    display: flex; flex-direction: column; gap: 12px;
    padding-top: 6px;
}
.etd-upload-submit {
    align-self: stretch;
    justify-content: center;
    padding: 12px 16px !important;
}
.etd-upload-progress-wrap {
    display: flex; flex-direction: column; gap: 6px;
}
.etd-upload-progress {
    appearance: none;
    -webkit-appearance: none;
    width: 100%; height: 6px;
    border: 0;
    border-radius: 3px;
    background: var(--etd-bg-alt);
    overflow: hidden;
}
.etd-upload-progress::-webkit-progress-bar {
    background: var(--etd-bg-alt);
    border-radius: 3px;
}
.etd-upload-progress::-webkit-progress-value {
    background: linear-gradient(90deg, var(--etd-primary), var(--etd-primary-hover));
    border-radius: 3px;
    transition: width .12s;
}
.etd-upload-progress::-moz-progress-bar {
    background: linear-gradient(90deg, var(--etd-primary), var(--etd-primary-hover));
    border-radius: 3px;
}
.etd-upload-progress[value="0"] { visibility: hidden; }
.etd-upload-status {
    font: 500 12.5px/1.4 var(--etd-mono);
    color: var(--etd-ink-quiet);
    margin: 0 !important;
    min-height: 1em;
}
.etd-upload-status i.fa { margin-right: 4px; color: inherit; }
.etd-upload-status font[color="red"] { color: var(--etd-danger, #B94141) !important; font-family: var(--etd-sans); }

/* Reference block - accepted-format chips */
.etd-upload-reference {
    background: var(--etd-bg-alt);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    padding: 14px 16px;
    margin-top: 4px;
}
.etd-upload-reference .etd-label-up { display: block; margin-bottom: 8px; }
.etd-upload-typelist {
    display: flex; flex-wrap: wrap; gap: 6px;
}
.etd-upload-type {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 9px;
    font: 500 11.5px/1 var(--etd-sans);
    color: var(--etd-ink);
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-sm);
}
.etd-upload-type i.fa { color: var(--etd-ink-quiet); font-size: 12px; }

/* File preview modal - full-viewport overlay that opens on
   filename click for PDFs + images (open_file_preview() in
   docs.js). Backdrop dims the app; the inner shell is a tall
   card carrying a header (title + open-in-tab + download + close)
   and a body that hosts either an <iframe> (PDF) or an <img>. */
.etd-preview-modal {
    position: fixed; inset: 0;
    z-index: 1400;
    display: none;
    align-items: center; justify-content: center;
    padding: 32px 24px;
}
.etd-preview-modal:not([hidden]),
.etd-preview-modal.etd-preview-open { display: flex; }
.etd-preview-backdrop {
    position: absolute; inset: 0;
    background: rgba(10, 21, 37, .55);
    animation: etd-preview-fade .15s ease-out;
}
@keyframes etd-preview-fade { from { opacity: 0; } to { opacity: 1; } }
.etd-preview-shell {
    position: relative;
    width: min(1080px, 96vw);
    height: min(92vh, 900px);
    background: var(--etd-surface);
    border-radius: var(--etd-radius-lg);
    box-shadow: 0 24px 64px rgba(10, 21, 37, .30);
    display: flex; flex-direction: column;
    overflow: hidden;
    animation: etd-preview-in .18s ease-out;
}
@keyframes etd-preview-in {
    from { opacity: 0; transform: translateY(8px) scale(.99); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
.etd-preview-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    background: var(--etd-surface);
    border-bottom: 1px solid var(--etd-rule);
}
.etd-preview-title-wrap {
    display: inline-flex; align-items: center; gap: 10px;
    min-width: 0; flex: 1;
}
.etd-preview-title-icon {
    color: var(--etd-primary);
    font-size: 15px;
    flex-shrink: 0;
}
.etd-preview-title {
    font: 600 14px/1.3 var(--etd-sans);
    color: var(--etd-ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    min-width: 0;
}
.etd-preview-actions {
    display: inline-flex; align-items: center; gap: 4px;
    flex-shrink: 0;
}
.etd-preview-action {
    appearance: none;
    width: 34px; height: 34px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 6px;
    border: 0;
    background: transparent;
    color: var(--etd-ink-quiet);
    cursor: pointer;
    text-decoration: none !important;
    font-size: 14px;
    transition: background .12s, color .12s;
}
.etd-preview-action:hover {
    background: var(--etd-bg-alt);
    color: var(--etd-ink);
}
.etd-preview-close { font-size: 22px; line-height: 1; }
.etd-preview-body {
    flex: 1;
    display: flex; align-items: center; justify-content: center;
    background: var(--etd-bg-alt);
    overflow: auto;
    min-height: 0;
}
.etd-preview-frame {
    width: 100%; height: 100%;
    border: 0;
    background: white;
}
.etd-preview-image {
    max-width: 100%; max-height: 100%;
    object-fit: contain;
    display: block;
}

/* Upload error banner - shown inside the drawer when the file
   storage configuration is missing. Keeps the drawer visible so
   the user gets a clear diagnostic instead of a blank panel. */
.etd-upload-error {
    display: flex; align-items: flex-start; gap: 14px;
    padding: 16px 18px;
    background: #FBF0DF;
    border: 1px solid #EAD3B4;
    border-radius: var(--etd-radius);
    color: #6B4A0F;
}
.etd-upload-error-icon {
    width: 32px; height: 32px;
    flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: #EAD3B4;
    color: #A0611B;
}
.etd-upload-error-icon i.fa { font-size: 14px; }
.etd-upload-error-title {
    font: 700 14px/1.3 var(--etd-sans);
    color: #A0611B;
    margin-bottom: 4px;
}
.etd-upload-error-hint {
    font-size: 12.5px;
    line-height: 1.55;
    color: #6B4A0F;
    margin: 0 !important;
}
.etd-upload-error-hint code {
    font-family: var(--etd-mono);
    background: rgba(255,255,255,0.55);
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 11.5px;
    color: #6B4A0F;
}

/* Legacy w3-sidenav reskin - the left-slidedown panels (series
   metadata bar, add-files bar, view-doc bar, dormant add-new-code
   bar, and the search panel where still triggered). Same tactic as
   the w3-modal reskin below: override the chrome from the outside
   so JS toggle behaviour (.css("display","block")/"none") remains
   the sole open/close mechanism, while the drawer visually reads as
   part of v0.2.

   Drawers slide in from the LEFT in the legacy code. We flip that to
   the right - it matches the modern-app expectation for detail
   drawers and stays out of the way of the topbar. */
.w3-sidenav {
    top: 0 !important;
    right: 0 !important; left: auto !important;
    height: 100vh !important;
    max-width: 100% !important;
    background: var(--etd-surface) !important;
    box-shadow: -12px 0 32px rgba(10, 21, 37, .12) !important;
    border-left: 1px solid var(--etd-rule) !important;
    z-index: 1300 !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    animation: etd-drawer-in .18s ease-out;
}
@keyframes etd-drawer-in {
    from { opacity: 0; transform: translateX(12px); }
    to   { opacity: 1; transform: translateX(0); }
}
.w3-sidenav > header,
.w3-sidenav > header.w3-container {
    background: var(--etd-surface) !important;
    color: var(--etd-ink) !important;
    padding: 20px 22px 14px !important;
    border-bottom: 1px solid var(--etd-rule) !important;
    position: sticky; top: 0; z-index: 1;
}
.w3-sidenav > header h2,
.w3-sidenav > header h3,
.w3-sidenav > header h4 {
    font: 600 17px/1.3 var(--etd-sans) !important;
    color: var(--etd-ink) !important;
    margin: 0 !important;
    letter-spacing: -0.005em !important;
}
.w3-sidenav > header i.fa {
    color: var(--etd-primary);
    margin-right: 8px;
}
.w3-sidenav > header .w3-closebtn {
    position: absolute; top: 14px; right: 14px;
    width: 30px; height: 30px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: transparent !important;
    color: var(--etd-ink-quiet) !important;
    font-size: 22px !important;
    line-height: 1 !important;
    cursor: pointer;
    transition: background .12s, color .12s;
}
.w3-sidenav > header .w3-closebtn:hover {
    background: var(--etd-bg-alt) !important;
    color: var(--etd-ink) !important;
}
/* Sidenav body - buttons, tags, tables inside adopt the same v0.2
   pill styling used for modal footers. */
.w3-sidenav .w3-button,
.w3-sidenav .w3-btn {
    appearance: none !important;
    display: inline-flex !important; align-items: center; gap: 8px;
    padding: 8px 14px !important;
    border-radius: var(--etd-radius) !important;
    font: 600 13px/1 var(--etd-sans) !important;
    cursor: pointer;
    text-decoration: none !important;
    box-shadow: none !important;
    border: 1px solid transparent !important;
    letter-spacing: 0 !important;
    text-transform: none !important;
    transition: background .12s, border-color .12s, color .12s;
}
.w3-sidenav .w3-button.w3-green,
.w3-sidenav .w3-btn.w3-green,
.w3-sidenav .w3-button.w3-blue,
.w3-sidenav .w3-btn.w3-blue,
.w3-sidenav .w3-button.w3-signal-blue,
.w3-sidenav .w3-btn.w3-signal-blue,
.w3-sidenav .w3-button.w3-signal-green,
.w3-sidenav .w3-btn.w3-signal-green {
    background: var(--etd-primary) !important;
    color: white !important;
    border-color: var(--etd-primary) !important;
}
.w3-sidenav .w3-button.w3-red,
.w3-sidenav .w3-btn.w3-red,
.w3-sidenav .w3-button.w3-signal-red,
.w3-sidenav .w3-btn.w3-signal-red {
    background: var(--etd-surface) !important;
    color: var(--etd-ink-quiet) !important;
    border-color: var(--etd-rule-strong) !important;
}
.w3-sidenav input.w3-input,
.w3-sidenav select.w3-select,
.w3-sidenav textarea.w3-input,
.w3-sidenav .w3-input,
.w3-sidenav .w3-select {
    border: 1px solid var(--etd-rule-strong) !important;
    border-radius: var(--etd-radius-sm) !important;
    padding: 10px 12px !important;
    font: 14px/1.4 var(--etd-sans) !important;
    background: var(--etd-surface) !important;
    color: var(--etd-ink) !important;
    box-shadow: none !important;
}
.w3-sidenav input.w3-input:focus,
.w3-sidenav select.w3-select:focus,
.w3-sidenav textarea.w3-input:focus,
.w3-sidenav .w3-input:focus,
.w3-sidenav .w3-select:focus {
    border-color: var(--etd-primary) !important;
    outline: 0 !important;
    box-shadow: 0 0 0 3px var(--etd-primary-soft) !important;
}
.w3-sidenav table.w3-table,
.w3-sidenav table.w3-table-all {
    font-size: 13px;
}
.w3-sidenav .w3-tag {
    background: var(--etd-primary-soft) !important;
    color: var(--etd-primary-ink) !important;
    padding: 4px 10px !important;
    border-radius: 999px !important;
    font: 600 11.5px/1.3 var(--etd-sans) !important;
    border: 1px solid var(--etd-primary-soft) !important;
    margin-right: 6px !important;
}

/* Legacy w3-modal reskin - the twelve confirmation modals across
   the app (delete-code, delete-release, create-new-release,
   delete-file, submit-for-review, disclaimer, missing metadata,
   missing file permissions, warning, success, series archive, and
   the outreach materials modal) all share the same w3-modal
   markup. Rather than rewriting each build_* method, we override
   the legacy chrome from the outside so they look native to v0.2
   without touching PHP.

   Display-toggle behaviour is untouched: legacy JS still flips
   $("#X").css("display","block") to open and "none" to close. */
.w3-modal {
    background: rgba(10, 21, 37, .45) !important;
    padding: 24px 20px !important;
    z-index: 1200 !important;
}
.w3-modal-content {
    background: var(--etd-surface) !important;
    border-radius: var(--etd-radius-lg) !important;
    box-shadow: 0 16px 40px rgba(10, 21, 37, .22) !important;
    max-width: 540px !important; width: min(540px, 100%) !important;
    margin: 4vh auto !important;
    overflow: hidden !important;
    animation: etd-modal-in .18s ease-out;
}
@keyframes etd-modal-in {
    from { opacity: 0; transform: translateY(-8px); }
    to   { opacity: 1; transform: translateY(0); }
}
/* Modal header - legacy uses <header class="w3-container w3-signal-blue|w3-signal-red|w3-signal-green|w3-blue-grey">.
   Neutralise the loud colour bar; leave a subtle divider instead so
   modal-type semantics come from the icon/copy, not chrome hue. */
.w3-modal-content > header,
.w3-modal-content > header.w3-container {
    background: var(--etd-surface) !important;
    color: var(--etd-ink) !important;
    padding: 20px 22px 14px !important;
    border-bottom: 1px solid var(--etd-rule) !important;
    position: relative;
}
.w3-modal-content > header h2,
.w3-modal-content > header h3,
.w3-modal-content > header h4 {
    font: 600 17px/1.3 var(--etd-sans) !important;
    color: var(--etd-ink) !important;
    margin: 0 !important;
    letter-spacing: -0.005em !important;
}
.w3-modal-content > header i.fa {
    color: var(--etd-primary);
    margin-right: 8px;
}
.w3-modal-content > header .w3-closebtn {
    position: absolute; top: 12px; right: 14px;
    width: 30px; height: 30px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: transparent !important;
    color: var(--etd-ink-quiet) !important;
    font-size: 22px !important;
    line-height: 1 !important;
    cursor: pointer;
    transition: background .12s, color .12s;
}
.w3-modal-content > header .w3-closebtn:hover {
    background: var(--etd-bg-alt) !important;
    color: var(--etd-ink) !important;
}
/* Modal body - the w3-container the header is followed by. Kept
   generic since some modals put buttons inline in the body. */
.w3-modal-content > .w3-container:not(header) {
    padding: 20px 22px 8px !important;
    color: var(--etd-ink);
    font-size: 14.5px;
    line-height: 1.55;
}
.w3-modal-content > .w3-container p { margin: 0 0 12px !important; }
.w3-modal-content > .w3-container p:last-child { margin-bottom: 0 !important; }
.w3-modal-content > .w3-container p b,
.w3-modal-content > .w3-container p strong { color: var(--etd-ink); }
.w3-modal-content > .w3-container i.fa-warning {
    color: var(--etd-accent);
}

/* Modal buttons - legacy uses w3-button or w3-btn plus a colour
   variant (w3-green = confirm, w3-red = cancel/destructive,
   w3-blue = neutral action). Restyle as v0.2 pills. */
.w3-modal-content .w3-button,
.w3-modal-content .w3-btn {
    appearance: none !important;
    display: inline-flex !important;
    align-items: center; gap: 8px;
    padding: 10px 18px !important;
    border-radius: var(--etd-radius) !important;
    font: 600 14px/1 var(--etd-sans) !important;
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
    text-decoration: none !important;
    margin: 4px 6px 4px 0 !important;
    box-shadow: none !important;
    border: 1px solid transparent !important;
    letter-spacing: 0 !important;
    text-transform: none !important;
}
/* Confirm / primary action (green in legacy → primary blue in v0.2). */
.w3-modal-content .w3-button.w3-green,
.w3-modal-content .w3-btn.w3-green,
.w3-modal-content .w3-button.w3-blue,
.w3-modal-content .w3-btn.w3-blue,
.w3-modal-content .w3-button.w3-signal-blue,
.w3-modal-content .w3-btn.w3-signal-blue,
.w3-modal-content .w3-button.w3-signal-green,
.w3-modal-content .w3-btn.w3-signal-green {
    background: var(--etd-primary) !important;
    color: white !important;
    border-color: var(--etd-primary) !important;
}
.w3-modal-content .w3-button.w3-green:hover,
.w3-modal-content .w3-btn.w3-green:hover,
.w3-modal-content .w3-button.w3-blue:hover,
.w3-modal-content .w3-btn.w3-blue:hover,
.w3-modal-content .w3-button.w3-signal-blue:hover,
.w3-modal-content .w3-btn.w3-signal-blue:hover,
.w3-modal-content .w3-button.w3-signal-green:hover,
.w3-modal-content .w3-btn.w3-signal-green:hover {
    background: var(--etd-primary-hover) !important;
    border-color: var(--etd-primary-hover) !important;
}
/* Cancel / destructive (red in legacy → ghost / accent in v0.2). */
.w3-modal-content .w3-button.w3-red,
.w3-modal-content .w3-btn.w3-red,
.w3-modal-content .w3-button.w3-signal-red,
.w3-modal-content .w3-btn.w3-signal-red {
    background: var(--etd-surface) !important;
    color: var(--etd-ink-quiet) !important;
    border-color: var(--etd-rule-strong) !important;
}
.w3-modal-content .w3-button.w3-red:hover,
.w3-modal-content .w3-btn.w3-red:hover,
.w3-modal-content .w3-button.w3-signal-red:hover,
.w3-modal-content .w3-btn.w3-signal-red:hover {
    color: var(--etd-danger, #B94141) !important;
    border-color: var(--etd-danger, #B94141) !important;
    background: var(--etd-surface) !important;
}
/* Cascade fix: some legacy buttons sit inside w3-margin containers
   or nest inline w3-padding - the button padding above wins because
   it is more specific + !important. Add a footer-ish alignment for
   trailing button rows so cancel + confirm sit at the bottom-right. */
.w3-modal-content > .w3-container:last-child {
    padding-bottom: 20px !important;
    display: flex; flex-wrap: wrap;
    align-items: flex-start;
}
.w3-modal-content > .w3-container:last-child > .w3-button,
.w3-modal-content > .w3-container:last-child > .w3-btn {
    margin-left: auto !important;
}
.w3-modal-content > .w3-container:last-child > .w3-button ~ .w3-button,
.w3-modal-content > .w3-container:last-child > .w3-btn ~ .w3-btn {
    margin-left: 0 !important;
}
/* Ensure any full-width paragraphs stay full-width inside the flex row. */
.w3-modal-content > .w3-container:last-child > p,
.w3-modal-content > .w3-container:last-child > div:not(.w3-button):not(.w3-btn) {
    flex: 1 0 100%;
    margin-left: 0 !important;
}

/* Result / confirmation blocks */
.etd-result { padding: 20px 24px; border-radius: var(--etd-radius-lg); border: 1px solid var(--etd-rule); background: var(--etd-surface); margin-bottom: 20px; }
.etd-result-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.etd-result-success { border-color: #BFE2CD; background: var(--etd-good-soft); }
.etd-result-success h2 { color: var(--etd-good); }
.etd-result-error   { border-color: #F1C3C1; background: var(--etd-crit-soft); }
.etd-result-error h2{ color: var(--etd-crit); }
.etd-result-pending { border-color: #EBD2A4; background: var(--etd-warn-soft); }
.etd-result-pending h2 { color: var(--etd-warn); }
.etd-result p   { color: var(--etd-ink); margin-top: 6px; }
.etd-result p + p { margin-top: 8px; }
.etd-result ul  { margin: 8px 0 0; padding-left: 20px; color: var(--etd-ink); }

/* ─── Admin - Reconcile user accounts (?c=admin_users) ─────────
   Suggested pairs panel above a full user directory; each pair
   or row exposes a "Merge into…" action that opens a preview
   dialog. Layout matches the outreach filter panel's rhythm so
   the two admin surfaces feel like a set. */

.etd-adm-suggest {
    background: var(--etd-surface);
    border: 1px solid #C7D5F4;
    border-radius: var(--etd-radius);
    box-shadow: 0 1px 2px rgb(15 23 42 / 0.04);
    margin-bottom: 18px;
    overflow: hidden;
}
.etd-adm-suggest-head {
    display: flex; align-items: center; gap: 12px;
    padding: 14px 18px;
    background: linear-gradient(180deg, var(--etd-primary-soft) 0%, rgba(238,245,251,0.35) 100%);
    border-bottom: 1px solid #C7D5F4;
}
.etd-adm-suggest-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    border-radius: 999px;
    background: var(--etd-surface);
    border: 1px solid #C7D5F4;
    color: var(--etd-primary);
    flex: 0 0 auto;
}
.etd-adm-suggest-icon i.fa { font-size: 15px; }
.etd-adm-suggest-heading {
    font: 600 14.5px/1.3 var(--etd-sans);
    color: var(--etd-primary-ink);
    letter-spacing: -0.005em;
}
.etd-adm-suggest-sub { font-size: 12px; color: var(--etd-ink-quiet); margin-top: 1px; }
.etd-adm-suggest-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.etd-adm-pair {
    display: grid;
    grid-template-columns: 200px 1fr auto;
    gap: 14px;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid var(--etd-rule);
}
.etd-adm-pair:last-child { border-bottom: 0; }
@media (max-width: 720px) {
    .etd-adm-pair { grid-template-columns: 1fr; align-items: stretch; }
}
.etd-adm-pair-reason {
    display: inline-flex; align-items: center; gap: 6px;
    font: 600 11px/1 var(--etd-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--etd-good);
    padding: 4px 10px;
    background: var(--etd-good-soft);
    border: 1px solid #BFE0CC;
    border-radius: 999px;
    justify-self: start;
}
.etd-adm-pair-reason i.fa { font-size: 11px; }
.etd-adm-pair-sides {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 12px;
    align-items: stretch;
    min-width: 0;
}
@media (max-width: 640px) {
    .etd-adm-pair-sides { grid-template-columns: 1fr; }
    .etd-adm-pair-arrow { justify-self: center; }
}
.etd-adm-pair-arrow {
    align-self: center;
    color: var(--etd-ink-faint);
    font-size: 18px;
}
.etd-adm-pair-actions { justify-self: end; }
@media (max-width: 720px) {
    .etd-adm-pair-actions { justify-self: stretch; }
    .etd-adm-pair-actions .btn-primary { width: 100%; }
}

.etd-adm-mini {
    padding: 10px 12px;
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    min-width: 0;
}
.etd-adm-mini-name {
    font: 600 13.5px/1.3 var(--etd-sans);
    color: var(--etd-ink);
    margin-bottom: 6px;
    word-break: break-word;
}
.etd-adm-mini-ids { display: flex; flex-wrap: wrap; gap: 4px; }

/* Directory */
.etd-adm-directory {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius);
    box-shadow: 0 1px 2px rgb(15 23 42 / 0.04);
    overflow: hidden;
}
.etd-adm-directory-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    padding: 14px 18px;
    background: var(--etd-bg-alt);
    border-bottom: 1px solid var(--etd-rule);
}
@media (max-width: 640px) {
    .etd-adm-directory-head { flex-direction: column; align-items: stretch; }
}
.etd-adm-directory-heading { font: 600 14.5px/1.3 var(--etd-sans); color: var(--etd-ink); }
.etd-adm-directory-sub { font-size: 12px; color: var(--etd-ink-quiet); margin-top: 1px; }
.etd-adm-directory-filter {
    position: relative;
    display: flex;
    flex: 0 0 auto;
    min-width: 240px;
}
.etd-adm-directory-filter > i.fa {
    position: absolute;
    left: 10px; top: 50%;
    transform: translateY(-50%);
    color: var(--etd-ink-faint);
    font-size: 12px;
    pointer-events: none;
}
.etd-adm-directory-filter input {
    width: 100%;
    padding: 8px 10px 8px 30px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    color: var(--etd-ink);
    font: 13px/1.4 var(--etd-sans);
    transition: border-color .12s, box-shadow .12s;
}
.etd-adm-directory-filter input:focus {
    outline: 0;
    border-color: var(--etd-primary);
    box-shadow: 0 0 0 3px var(--etd-primary-soft);
}
.etd-adm-user-list { display: flex; flex-direction: column; }
.etd-adm-user {
    display: grid;
    grid-template-columns: 220px 1fr auto;
    gap: 14px;
    align-items: center;
    padding: 12px 18px;
    border-bottom: 1px solid var(--etd-rule);
}
.etd-adm-user:last-child { border-bottom: 0; }
.etd-adm-user:hover { background: var(--etd-bg-alt); }
@media (max-width: 720px) {
    .etd-adm-user { grid-template-columns: 1fr; }
}
.etd-adm-user-name { min-width: 0; }
.etd-adm-user-primary {
    font: 600 14px/1.3 var(--etd-sans);
    color: var(--etd-ink);
    word-break: break-word;
}
.etd-adm-user-activity {
    font-size: 11.5px;
    color: var(--etd-ink-quiet);
    margin-top: 1px;
    font-variant-numeric: tabular-nums;
}
.etd-adm-user-ids { display: flex; flex-wrap: wrap; gap: 4px; min-width: 0; }
.etd-adm-user-action .btn-quiet { padding: 6px 12px; font-size: 12.5px; }

/* Identifier pills - subtle differentiation per identity type. */
.etd-adm-id {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 8px;
    border-radius: 999px;
    font: 500 11px/1.3 var(--etd-sans);
    background: var(--etd-bg-alt);
    color: var(--etd-ink);
    border: 1px solid var(--etd-rule);
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}
.etd-adm-id .etd-adm-id-key {
    font: 700 9.5px/1 var(--etd-sans);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--etd-ink-quiet);
}
.etd-adm-id-legacy { background: var(--etd-primary-soft); border-color: #C7D5F4; color: var(--etd-primary-ink); }
.etd-adm-id-ad     { background: #FCDCDC; border-color: #F1BEBE; color: #B94141; }
.etd-adm-id-iam    { background: #EDE1FA; border-color: #DAC8F0; color: #5C39A0; }
.etd-adm-id-etmd   { background: #D9F1E3; border-color: #B7DFC7; color: #1F6E5A; }

/* Dialog */
.etd-adm-dialog {
    position: fixed; inset: 0;
    background: rgb(15 23 42 / 0.45);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    display: flex; align-items: center; justify-content: center;
    padding: 24px;
    z-index: 1400;
}
.etd-adm-dialog-body {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: 14px;
    box-shadow: 0 20px 45px rgb(15 23 42 / 0.18);
    width: min(720px, calc(100vw - 2rem));
    max-height: calc(100vh - 3rem);
    display: grid;
    grid-template-rows: auto 1fr auto;
    overflow: hidden;
}
.etd-adm-dialog-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid var(--etd-rule);
}
.etd-adm-dialog-head h2 {
    margin: 0;
    font: 600 16px/1.3 var(--etd-sans);
    color: var(--etd-ink);
}
.etd-adm-dialog-close {
    width: 30px; height: 30px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px;
    background: transparent;
    border: 0;
    color: var(--etd-ink-quiet);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    transition: background .12s, color .12s;
}
.etd-adm-dialog-close:hover { background: var(--etd-bg-alt); color: var(--etd-ink); }
.etd-adm-dialog-content {
    padding: 18px 20px;
    overflow-y: auto;
    display: flex; flex-direction: column; gap: 14px;
}
.etd-adm-dialog-hint {
    margin: 0;
    font-size: 13px;
    color: var(--etd-ink-quiet);
    line-height: 1.5;
}
.etd-adm-dialog-picker {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 12px;
    align-items: end;
}
@media (max-width: 560px) {
    .etd-adm-dialog-picker { grid-template-columns: 1fr; }
    .etd-adm-dialog-arrow  { justify-self: center; }
}
.etd-adm-dialog-arrow { color: var(--etd-ink-faint); font-size: 20px; }
.etd-adm-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.etd-adm-field-label {
    font: 600 11px/1 var(--etd-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--etd-ink-quiet);
}
.etd-adm-field select {
    padding: 8px 10px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    color: var(--etd-ink);
    font: 13px/1.4 var(--etd-sans);
}
.etd-adm-field select:focus {
    outline: 0;
    border-color: var(--etd-primary);
    box-shadow: 0 0 0 3px var(--etd-primary-soft);
}
.etd-adm-preview {
    border: 1px solid var(--etd-rule);
    border-radius: var(--etd-radius-sm);
    padding: 12px;
    background: var(--etd-bg-alt);
}
.etd-adm-preview-empty { margin: 0; color: var(--etd-ink-quiet); font-size: 13px; }
.etd-adm-preview-tbl {
    width: 100%;
    border-collapse: collapse;
    font-size: 12.5px;
}
.etd-adm-preview-tbl th,
.etd-adm-preview-tbl td {
    padding: 6px 8px;
    border-bottom: 1px solid var(--etd-rule);
    text-align: left;
    vertical-align: top;
}
.etd-adm-preview-tbl thead th {
    font: 600 10.5px/1.3 var(--etd-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--etd-ink-quiet);
    background: var(--etd-surface);
}
.etd-adm-preview-tbl tbody th {
    font: 600 12px/1.3 var(--etd-sans);
    color: var(--etd-ink-quiet);
    white-space: nowrap;
    width: 22%;
}
.etd-adm-preview-tbl tbody tr:last-child th,
.etd-adm-preview-tbl tbody tr:last-child td { border-bottom: 0; }
.etd-adm-carried {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--etd-good-soft);
    border: 1px solid #BFE0CC;
    color: var(--etd-good);
    font: 600 9.5px/1.3 var(--etd-sans);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}
.etd-adm-preview-count {
    margin: 8px 0 0;
    font-size: 12.5px;
    color: var(--etd-ink);
}
.etd-adm-dialog-foot {
    display: flex; gap: 10px; justify-content: flex-end;
    padding: 14px 20px;
    border-top: 1px solid var(--etd-rule);
    background: var(--etd-bg-alt);
}

/* Top-level filter above the Reconcile suggestions + directory.
   One search input drives both surfaces so an admin can zero in
   on a person across the whole page in one place. */
.etd-adm-topfilter {
    margin-bottom: 16px;
}
.etd-adm-topfilter-inner {
    position: relative;
    display: flex; align-items: center;
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius);
    box-shadow: 0 1px 2px rgb(15 23 42 / 0.04);
    padding: 4px 12px 4px 40px;
    transition: border-color .12s, box-shadow .12s;
}
.etd-adm-topfilter-inner:focus-within {
    border-color: var(--etd-primary);
    box-shadow: 0 0 0 3px var(--etd-primary-soft);
}
.etd-adm-topfilter-inner > i.fa {
    position: absolute;
    left: 14px; top: 50%;
    transform: translateY(-50%);
    color: var(--etd-primary);
    font-size: 14px;
    pointer-events: none;
}
.etd-adm-topfilter-inner input {
    flex: 1;
    border: 0;
    background: transparent;
    color: var(--etd-ink);
    padding: 10px 4px;
    font: 14.5px/1.4 var(--etd-sans);
}
.etd-adm-topfilter-inner input:focus { outline: 0; }
.etd-adm-topfilter-clear {
    width: 26px; height: 26px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 0;
    background: var(--etd-bg-alt);
    border-radius: 999px;
    color: var(--etd-ink-quiet);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    transition: background .12s, color .12s;
}
.etd-adm-topfilter-clear:hover { background: var(--etd-rule-strong); color: var(--etd-ink); }

/* No-match button on a suggested pair - subtle danger tint that
   sits alongside the primary Merge action without competing with
   it for attention. */
.etd-adm-pair-nomatch {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 12px;
    border-radius: var(--etd-radius);
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule-strong);
    color: var(--etd-ink-quiet);
    font: 600 12.5px/1 var(--etd-sans);
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
    margin-left: 8px;
}
.etd-adm-pair-nomatch:hover {
    background: var(--etd-crit-soft);
    border-color: #ECC0BE;
    color: var(--etd-crit);
}
.etd-adm-pair-nomatch:focus-visible { outline: 2px solid var(--etd-crit); outline-offset: 2px; }
.etd-adm-pair-nomatch i.fa { font-size: 11px; }
@media (max-width: 720px) {
    .etd-adm-pair-nomatch { margin-left: 0; width: 100%; justify-content: center; }
}

/* Empty-state panels for suggestions + directory. */
.etd-adm-suggest-empty,
.etd-adm-directory-empty {
    padding: 24px 18px;
    text-align: center;
    color: var(--etd-ink-quiet);
    font-size: 13px;
}
.etd-adm-suggest-empty p { margin: 0; }
.etd-adm-suggest-empty p + p { margin-top: 4px; }
.etd-adm-suggest-empty strong { color: var(--etd-ink); }

/* Swap button between source + target selects in the merge dialog. */
.etd-adm-dialog-picker { grid-template-columns: 1fr auto 1fr; align-items: end; }
.etd-adm-dialog-swap {
    display: inline-flex; flex-direction: column; align-items: center; gap: 2px;
    padding: 8px 10px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    color: var(--etd-ink-quiet);
    font: 600 10px/1 var(--etd-sans);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background .12s, color .12s, border-color .12s;
    align-self: end;
    height: 40px;
    min-width: 44px;
}
.etd-adm-dialog-swap i.fa { font-size: 13px; }
.etd-adm-dialog-swap:hover {
    background: var(--etd-primary-soft);
    color: var(--etd-primary);
    border-color: #C7D5F4;
}
.etd-adm-dialog-swap:focus-visible {
    outline: 2px solid var(--etd-primary);
    outline-offset: 2px;
}
.etd-adm-dialog-swap-label { font-size: 9.5px; }
@media (max-width: 560px) {
    .etd-adm-dialog-swap {
        flex-direction: row; height: auto; width: 100%;
        padding: 8px 12px;
        justify-content: center;
        margin: 4px 0;
    }
    .etd-adm-dialog-swap i.fa { transform: rotate(90deg); }
}

/* Pagination footer under the directory. */
.etd-adm-pagination {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
    padding: 12px 18px;
    border-top: 1px solid var(--etd-rule);
    background: var(--etd-bg-alt);
}
.etd-adm-perpage {
    display: inline-flex; align-items: center; gap: 8px;
    font-size: 12.5px;
    color: var(--etd-ink-quiet);
}
.etd-adm-perpage-label { letter-spacing: 0.02em; }
.etd-adm-perpage select {
    padding: 4px 8px;
    border: 1px solid var(--etd-rule-strong);
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    color: var(--etd-ink);
    font: 12.5px/1.4 var(--etd-sans);
}
.etd-adm-pager {
    display: inline-flex; align-items: center; gap: 8px;
}
.etd-adm-page-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px;
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule-strong);
    color: var(--etd-ink);
    font: 600 12px/1 var(--etd-sans);
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
}
.etd-adm-page-btn:hover:not(:disabled) {
    background: var(--etd-primary-soft);
    border-color: var(--etd-primary);
    color: var(--etd-primary-ink);
}
.etd-adm-page-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
.etd-adm-page-btn i.fa { font-size: 10px; }
.etd-adm-page-status {
    font: 500 12px/1 var(--etd-sans);
    color: var(--etd-ink-quiet);
    font-variant-numeric: tabular-nums;
    padding: 0 8px;
}

/* Explicit hide classes for the Reconcile directory rows AND the
   suggested-pairs list.  Uses !important so the class beats the
   base display rules (grid / flex) without relying on the
   browser's [hidden] behaviour, which can be shadowed by other
   author styles. */
.etd-adm-user.is-filter-hidden,
.etd-adm-user.is-page-hidden,
.etd-adm-pair.is-filter-hidden,
.etd-adm-pair.is-page-hidden { display: none !important; }

/* Shared confirm modal - replaces window.confirm() for destructive
   actions on the Reconcile page.  Same visual language as
   .etd-adm-dialog so the two feel like a set. */
.etd-adm-confirm {
    position: fixed; inset: 0;
    background: rgb(15 23 42 / 0.45);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    display: flex; align-items: center; justify-content: center;
    padding: 24px;
    z-index: 1500;
}
.etd-adm-confirm-body {
    background: var(--etd-surface);
    border: 1px solid var(--etd-rule);
    border-radius: 14px;
    box-shadow: 0 20px 45px rgb(15 23 42 / 0.22);
    width: min(460px, calc(100vw - 2rem));
    display: grid;
    grid-template-rows: auto 1fr auto;
    overflow: hidden;
    animation: etd-adm-confirm-in 160ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes etd-adm-confirm-in {
    from { transform: translateY(6px) scale(0.985); opacity: 0; }
    to   { transform: translateY(0)   scale(1);      opacity: 1; }
}
.etd-adm-confirm-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid var(--etd-rule);
    background: var(--etd-crit-soft);
}
.etd-adm-confirm-head h2 {
    margin: 0;
    font: 600 15.5px/1.3 var(--etd-sans);
    color: var(--etd-crit);
    letter-spacing: -0.005em;
}
.etd-adm-confirm-close {
    width: 28px; height: 28px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px;
    background: transparent;
    border: 0;
    color: var(--etd-ink-quiet);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    transition: background .12s, color .12s;
}
.etd-adm-confirm-close:hover { background: rgb(255 255 255 / 0.5); color: var(--etd-ink); }
.etd-adm-confirm-content {
    padding: 18px 20px;
    color: var(--etd-ink);
    font-size: 14px;
    line-height: 1.5;
}
.etd-adm-confirm-content p { margin: 0; }
.etd-adm-confirm-content p + p { margin-top: 8px; }
.etd-adm-confirm-note {
    color: var(--etd-ink-quiet);
    font-size: 12.5px;
    line-height: 1.5;
    padding-left: 12px;
    border-left: 3px solid var(--etd-rule-strong);
}
.etd-adm-confirm-foot {
    display: flex; gap: 10px; justify-content: flex-end;
    padding: 14px 20px;
    border-top: 1px solid var(--etd-rule);
    background: var(--etd-bg-alt);
}

/* Reconcile-page group chips - one per persisted AD CN / IAM path.
   Slot into the identifier-pill row so a user's identity + group
   membership read as one visual block, with a subtle tint per
   source so the eye distinguishes AD from IAM at a glance. */
.etd-adm-groups {
    display: inline-flex; flex-wrap: wrap; gap: 4px;
    align-items: center;
    margin-left: 4px;
}
.etd-adm-group {
    display: inline-flex; align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    font: 500 10.5px/1.3 var(--etd-sans);
    letter-spacing: 0.02em;
    white-space: nowrap;
    max-width: 22ch;
    overflow: hidden; text-overflow: ellipsis;
}
.etd-adm-group-ad   { background: #FCEDED; border: 1px solid #ECC0BE; color: var(--etd-crit); }
.etd-adm-group-iam  { background: #EDE1FA; border: 1px solid #DAC8F0; color: #5C39A0; font-family: var(--etd-mono); font-size: 10px; }
.etd-adm-group-more {
    background: var(--etd-bg-alt);
    border: 1px dashed var(--etd-rule-strong);
    color: var(--etd-ink-quiet);
    cursor: help;
}
.etd-adm-groups-synced {
    display: inline-flex; align-items: center; gap: 4px;
    color: var(--etd-ink-faint);
    font-size: 10.5px;
    font-family: var(--etd-mono);
    font-variant-numeric: tabular-nums;
    margin-left: 2px;
}
.etd-adm-groups-synced i.fa { font-size: 10px; }

/* Access-chip row wrapper - used by the Codifier + Recent-docs
   tables to lay out multiple access-level chips inline with a
   consistent gap.  Chip pill styling comes from .etd-om-access. */
.etd-om-access-row { display: inline-flex; flex-wrap: wrap; gap: 4px; }

/* Admin "view as non-admin" preview banner - sits under the
   topbar for the whole session while the flag is on so the
   admin can never forget they've suppressed their own bypass. */
.etd-adm-downgrade-banner {
    background: linear-gradient(180deg, var(--etd-warn-soft) 0%, #fff6e5 100%);
    border-bottom: 1px solid #E6CE9C;
    color: var(--etd-ink);
    font: 500 13px/1.4 var(--etd-sans);
}
.etd-adm-downgrade-badge {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--etd-warn);
    color: #fff;
    font: 700 10.5px/1 var(--etd-sans);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    flex: 0 0 auto;
}
.etd-adm-downgrade-badge i.fa { font-size: 10px; }
.etd-adm-downgrade-text { color: var(--etd-ink); flex: 1 1 auto; min-width: 0; }
.etd-adm-downgrade-text strong { color: var(--etd-warn); }
.etd-adm-downgrade-restore {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 12px;
    border-radius: var(--etd-radius-sm);
    background: var(--etd-surface);
    border: 1px solid #E6CE9C;
    color: var(--etd-warn);
    font: 600 12px/1 var(--etd-sans);
    text-decoration: none !important;
    flex: 0 0 auto;
    transition: background .12s, color .12s;
}
.etd-adm-downgrade-restore:hover {
    background: var(--etd-warn);
    color: #fff !important;
    border-color: var(--etd-warn);
}

/* Footer links - accessible default + strong hover / focus.
   The old hover:text-n-600 change was almost invisible against
   the n-500 baseline; this styling gives the link a thin
   default underline with a bit of offset (readable but not
   loud), lifts the colour to accent on hover and adds an
   underline weight bump, and shows a proper focus ring for
   keyboard users. */
.etd-footer-link {
    color: var(--etd-primary);
    text-decoration: underline;
    text-decoration-color: var(--etd-rule-strong);
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    transition: color .12s, text-decoration-color .12s, text-decoration-thickness .12s;
    padding: 2px 2px;
    border-radius: 3px;
}
.etd-footer-link:hover {
    color: var(--etd-primary-hover);
    text-decoration-color: var(--etd-primary);
    text-decoration-thickness: 2px;
}
.etd-footer-link:focus-visible {
    outline: 2px solid var(--etd-primary);
    outline-offset: 2px;
    color: var(--etd-primary-hover);
    text-decoration-color: var(--etd-primary);
}

/* Danger button - solid red, white text.  Used by the doc-detail
   page's admin hard-delete affordance in the Danger card, plus the
   confirm button in the type-to-confirm modal.  Falls back to a
   plain CSS pill rather than Tailwind red-6* utilities because the
   compiled tailwind.build.css only ships the light red shades
   (red-50 / -200 / -700 / -800) used by the danger card itself. */
.etd-danger-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 6px;
    border: 1px solid #b91c1c;
    background: #dc2626;
    color: #ffffff;
    font: 600 13px/1.3 var(--etd-sans);
    cursor: pointer;
    transition: background .12s, border-color .12s, box-shadow .12s;
}
.etd-danger-btn:hover:not(:disabled) {
    background: #b91c1c;
    border-color: #991b1b;
}
.etd-danger-btn:focus-visible {
    outline: 2px solid #dc2626;
    outline-offset: 2px;
}
.etd-danger-btn:disabled {
    background: #fca5a5;
    border-color: #f87171;
    color: #ffffff;
    cursor: not-allowed;
}

/* Primary + ghost buttons - unscoped counterparts to
   .etd-scope .etd-button-accent / .etd-button-ghost.  Used by
   forms that live outside .etd-scope (e.g. the review-triage
   form) so buttons keep their fill / border / focus states
   regardless of parent context.  Same shape + palette as the
   scoped equivalents; matched to .etd-danger-btn's height and
   focus-ring convention so a row of Cancel / Submit / Delete
   reads as a coherent set. */
.etd-btn-primary,
.etd-btn-ghost {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 16px;
    border-radius: 6px;
    font: 600 14px/1.3 var(--etd-sans);
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s, box-shadow .12s;
    text-decoration: none;
    min-height: 40px;
}
.etd-btn-primary {
    background: var(--etd-primary);
    border: 1px solid var(--etd-primary);
    color: #ffffff;
}
.etd-btn-primary:hover:not(:disabled) {
    background: var(--etd-primary-hover);
    border-color: var(--etd-primary-hover);
    color: #ffffff;
    text-decoration: none;
}
.etd-btn-primary:focus-visible {
    outline: 2px solid var(--etd-primary);
    outline-offset: 2px;
}
.etd-btn-primary:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}
.etd-btn-ghost {
    background: transparent;
    border: 1px solid var(--etd-rule-strong);
    color: var(--etd-ink-quiet);
}
.etd-btn-ghost:hover {
    border-color: var(--etd-ink-faint);
    color: var(--etd-ink);
    background: var(--etd-bg-alt);
    text-decoration: none;
}
.etd-btn-ghost:focus-visible {
    outline: 2px solid var(--etd-primary);
    outline-offset: 2px;
}

/* ============================================================
   Force light theme (interim fix, reported by Nicola 2026-09-28).

   Background: tailwind.build.css (shared source with etmd-next)
   carries an @media (prefers-color-scheme: dark) block that
   inverts the --color-n-* palette + shadow tokens.  et-docs.css
   defines its own --etd-* palette with NO dark variants, so on
   a dark-mode OS the header + Tailwind-styled cards flip dark
   while every .etd-* panel stays light - the site renders in a
   mixed state.

   Fix: hard-override the --color-n-* palette back to its light
   values inside the same dark media query so the whole page
   stays consistent, and pin color-scheme: only light so Chrome
   auto-darkening + native form controls also stay light.  This
   file loads after tailwind.build.css and is unlayered, so it
   wins on cascade order.

   A proper dark mode (all --etd-* tokens get dark variants,
   the 166 inline hex colours get audited or overridden, and a
   3-state system/light/dark toggle lands in the header) is a
   separate deliberate piece of work - tracked outside this
   file.
   ============================================================ */
:root { color-scheme: only light; }
@media (prefers-color-scheme: dark) {
  :root {
    --color-n-0:   #fff;
    --color-n-50:  #f7f8fa;
    --color-n-100: #eef1f5;
    --color-n-200: #dde2eb;
    --color-n-300: #c1c9d6;
    --color-n-400: #8892a3;
    --color-n-500: #5a6473;
    --color-n-600: #3f4855;
    --color-n-700: #2b323c;
    --color-n-800: #1a1f27;
    --color-n-900: #0e1218;
    --shadow-card:   0 1px 2px #0e12180a, 0 4px 12px #0e12180f;
    --shadow-pop:    0 6px 20px #0e12181a, 0 2px 6px #0e12180d;
    --shadow-accent: 0 6px 20px #207cca33, 0 2px 8px #207cca1f;
  }
}
