/* ==========================================================================
   3DOptix redesign — GENERIC ARCHIVE page-unique CSS.

   Depends on: dxr-tokens.css -> dxr-components.css -> dxr-shell.css
   Enqueued CONDITIONALLY from archive.php (handle 'dxr-page-archive',
   dependency 'dxr-shell'), so it ships on archive URLs only and can never
   reorder the shared layer.

   WHAT IT SERVES. Every listing surface with no more specific template:
   /video/, /academy-post/, /academy-cat/<slug>/, the other CPT category
   taxonomies, and core's category / tag / author / date archives. See the
   docblock in archive.php for why it cannot reach /blog/, /videos/,
   /use-cases/, /academy/ or the WooCommerce store.

   DESIGN SOURCE. The approved prototype contains exactly ONE collection view —
   the Academy index, '3DOptix Website.dc.html' lines 628-741 — and every
   structure below is transcribed from it, the same source the blog index, Use
   Cases and Videos stylesheets were written from. That is deliberate: a stray
   archive should read as the same system as the curated lists, not as a
   fifth invention. Line references below point at that block.

   RULES FOR THIS FILE:
   - SCOPE. Every selector is scoped to .dxr-page-archive, the wrapper class
     archive.php emits inside the shell's <main>. No bare element selectors,
     ever. Sibling templates were written in parallel by other agents and share
     component names — the page scope is what keeps the files from having to
     agree.
   - No new colour. Every value resolves from the token layer; the only raw
     numbers are geometry transcribed from the prototype, and each is named in
     §0 rather than repeated as a literal below.
   - No new keyframe. The only motion here is a border-colour transition,
     already neutralised by the shared prefers-reduced-motion block in
     dxr-components.css §2.
   - The spectrum gradient appears ZERO times in this file. Site-wide budget
     unchanged: nav 2px + footer 3px.

   Contents
     §0  Page-local custom properties
     §1  Header band — dark
     §2  Archive description
     §2b The ONE reset re-declaration, and why it lives here
     §3  Result count line
     §4  Card grid + card
     §5  Pagination
     §6  Empty state
   ========================================================================== */


/* ==========================================================================
   §0 Page-local custom properties

   Prototype values with no entry in the token layer. Declared once, used by
   name below, so every literal in this file is traceable to a prototype line
   and a design change is a one-line edit. Values are deliberately identical to
   dxr-page-blog.css §0 — the two screens ARE the same collection view, and
   drifting them apart by a few pixels would be the only visible difference
   between a curated list and a stray archive.
   ========================================================================== */
.dxr-page-archive{
  --dxr-arch-head-top:clamp(27px,3.3vw,44px);   /* proto 632 */
  --dxr-arch-head-bot:clamp(32px,3.9vw,52px);   /* proto 632 */
  --dxr-arch-gap:24px;                          /* proto 659 — NOT --dxr-gap-panels (20px) */
  --dxr-arch-page-h:44px;                        /* pagination cell — see §5. 44px, not
                                                    40: the cell is a touch target and
                                                    the design transcribes no value. */
}


/* ==========================================================================
   §1 Header band — dark (proto 630-639)

   Deliberately NOT .dxr-hero: no glow, no CTA row, no spectrum eyebrow bar. An
   archive is a directory, not a pitch. The 64px blueprint is the design's one
   documented 64px instance and .dxr-blueprint--64 already exists for it.

   The rhythm is the prototype's, not the system's, so .dxr-section's
   --dxr-section-y is overridden here rather than in the shared layer. The
   two-class selector outranks .dxr-section (0,1,0) without !important.
   ========================================================================== */
.dxr-page-archive .dxr-arch__head{
  padding:var(--dxr-arch-head-top) 0 var(--dxr-arch-head-bot);
}

/* The breadcrumb occupies the eyebrow slot — it is already mono, and it is
   already real content on this page. That is why dxr_eyebrow() is not called. */
.dxr-page-archive .dxr-arch__crumbs{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin-bottom:24px;
  font:400 12px/1 var(--dxr-font-mono);
  color:var(--dxr-on-dark-caption);
}
.dxr-page-archive .dxr-arch__crumbs a{position:relative;color:var(--dxr-on-dark-body-alt)}
.dxr-page-archive .dxr-arch__crumbs a:hover{color:var(--dxr-on-dark)}
/* TOUCH TARGET. The 12px mono line box gives the crumb link a ~12px-tall hit
   area. The pseudo-element enlarges the hit area WITHOUT moving anything:
   12 + 16 + 16 = 44px tall, and 4px of horizontal bleed against the row's 10px
   gap leaves the neighbouring crumb its own 2px of clearance. The band's top
   padding is >=27px and the row's margin-bottom is 24px, so the overhang never
   reaches another control. Same construction as dxr-page-blog.css §1. */
.dxr-page-archive .dxr-arch__crumbs a::after{
  content:"";position:absolute;inset:-16px -4px;
}

/* Prototype 636. Smaller than .dxr-h1--page on purpose — an index H1 is not a
   product H1. The shared type file is off-limits to this batch, so the role is
   authored here rather than added to §4 of dxr-components.css, exactly as
   .dxr-blog__title is.

   overflow-wrap is load-bearing HERE in a way it is not on the blog: the string
   is core's own archive title and can be a 40-character unbroken tag slug or a
   term name with no spaces at all. At 800 weight and the clamp minimum that
   overflows the 280px content box a 320px viewport leaves, and nothing in the
   ancestor chain clips or scrolls — the document itself would scroll sideways.
   `break-word` (not `anywhere`) cannot affect any track sizing. */
.dxr-page-archive .dxr-arch__title{
  margin:0;
  font:800 clamp(27px,4.2vw,46px)/1.08 var(--dxr-font-sans);
  letter-spacing:-.038em;
  color:var(--dxr-on-dark);
  overflow-wrap:break-word;
}
/* Core wraps the archive NAME in a bare <span> and leaves the prefix
   ("Category:", "Archives:", "Year:") outside it — see get_the_archive_title().
   The span is styled to inherit rather than left to chance: a UA or a plugin
   stylesheet reaching a bare <span> inside an <h1> would otherwise be the only
   thing deciding how half this heading looks. */
.dxr-page-archive .dxr-arch__title span{font:inherit;color:inherit;letter-spacing:inherit}


/* ==========================================================================
   §2 Archive description

   Term and author descriptions. Empty on nearly every archive on this site
   today, so the template renders the whole block conditionally and there is no
   collapsed-empty case to style.

   Measure is capped at the shared 620px reading width — the same measure the
   list pages give their lede — because this sits under a 46px heading on a full
   1300px container, and a description running the whole width would be the only
   unmeasured prose in the design.
   ========================================================================== */
.dxr-page-archive .dxr-arch__desc{
  max-width:min(100%,620px);
  margin-top:14px;
  font:400 15px/1.7 var(--dxr-font-sans);
  color:var(--dxr-on-dark-body);
}


/* ==========================================================================
   §2b THE ONE RESET RE-DECLARATION — read this before touching §2

   archive.php is a 'chrome' surface: everything it prints is esc_html()'d into
   an element it authored, so dxr-prose.css is NOT loaded. The single exception
   is this block — get_the_archive_description() is EDITOR CONTENT, emitted
   through wp_kses_post(), so it can legitimately contain <p>, <ul>, <ol>, <em>
   and <a>.

   dxr-components.css §1 resets exactly those:
       .dxr-shell--dxr :where(p){margin:0}                        (0,1,0)
       .dxr-shell--dxr :where(ul,ol){margin:0;padding:0;list-style:none}  (0,1,0)
       .dxr-shell--dxr :where(a){text-decoration:none}            (0,1,0)

   Left alone, a two-paragraph term description would render as one run-on
   block, a bulleted list would lose its markers and its indent, and its links
   would be indistinguishable from body text on a dark ground. Every rule below
   PUTS ONE OF THOSE BACK, positively, in this design's type scale.

   WHY NOT dxr-prose.css. Two reasons, both about it being the wrong tool, not
   about it being unavailable:
     1. It is tuned for an article body — 17px/1.8 in #334155 on white. This
        description sits in a DARK band, where that ink is invisible. Importing
        a 35KB layer and then overriding every property that matters is more
        code and more risk than the six rules below.
     2. The contract's mode table assigns 'chrome' to this surface, and 'prose'
        would also pull the layer onto every one of the eight-plus URL shapes
        this file serves, for a block that is empty on nearly all of them.

   SPECIFICITY IS ARITHMETIC, NOT !important. The reset scores (0,1,0) because
   its element half is wrapped in :where(). Every selector below is
   `.dxr-page-archive .dxr-arch__desc <element>` = (0,2,1), which outranks it
   outright and does not depend on source order.

   IF THIS BLOCK GROWS. The moment a second surface needs it, promote it — do
   not copy it. A third copy is how two archives start rendering the same term
   description differently.
   ========================================================================== */
.dxr-page-archive .dxr-arch__desc p{margin:0 0 12px}
.dxr-page-archive .dxr-arch__desc p:last-child{margin-bottom:0}
.dxr-page-archive .dxr-arch__desc ul,
.dxr-page-archive .dxr-arch__desc ol{margin:0 0 12px;padding-left:20px}
.dxr-page-archive .dxr-arch__desc ul{list-style:disc}
.dxr-page-archive .dxr-arch__desc ol{list-style:decimal}
.dxr-page-archive .dxr-arch__desc li{margin-bottom:6px}
/* .dxr-section--dark a already supplies --dxr-cyan-light at (0,1,1); only the
   underline has to come back, and it is what makes a link in running prose
   identifiable without relying on colour alone (WCAG 1.4.1). */
.dxr-page-archive .dxr-arch__desc a{text-decoration:underline}


/* ==========================================================================
   §3 Result count line (proto 654-657)

   The list pages' results line, minus its heading: the archive title is already
   the H1 two rules above, so repeating it here would be the only duplicated
   string on the page. Mono, because a count is measured content.

   ACCESSIBILITY: --dxr-text-subtle is 3.69:1 on white and fails WCAG AA at this
   size. It is a client-approved palette value — see the note in dxr-tokens.css
   §1.2. Do not darken it here; escalate.
   ========================================================================== */
.dxr-page-archive .dxr-arch__count{
  font:400 13px/1 var(--dxr-font-mono);
  color:var(--dxr-text-subtle);
}


/* ==========================================================================
   §4 Card grid + card (proto 659-726)

   320px / 3-up is the tuned --dxr-min-3up: at the 1300px container the usable
   width is 1220px, so the row resolves to 3 x 390px (a 4th column would need
   4*320 + 3*24 = 1352px). The card carries a 16/9 image, an optional mono
   kicker, a title, a three-line excerpt and a meta line — content-bearing
   cells, which is exactly what --dxr-min-3up is documented for. The minimum is
   NOT to be retuned here.
   ========================================================================== */
.dxr-page-archive .dxr-arch__grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--dxr-min-3up)),1fr));
  gap:var(--dxr-arch-gap);
}
/* The 36px is the gap BETWEEN the count line and the grid, so it is declared on
   the adjacency and not on the grid itself. The count line is filterable off,
   and it is suppressed on an empty archive — in either case the band's own
   --dxr-section-y already supplies the opening rhythm, and an unconditional
   margin here would add a second, larger gap above the first card for no
   reason. Same reasoning for the empty state in §6. */
.dxr-page-archive .dxr-arch__count + .dxr-arch__grid{margin-top:36px}

/* Prototype 661: bordered, 12px radius, no background of its own, so the body
   sits on the sunken ground. Hover moves the BORDER only — the system owns
   exactly three shadows and none of them is a card shadow, so no lift and no
   scale. */
.dxr-page-archive .dxr-arch__card{
  display:flex;flex-direction:column;
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-radius-panel);
  overflow:hidden;
  color:inherit;
  transition:border-color .15s ease;
}
.dxr-page-archive .dxr-arch__card:hover{border-color:var(--dxr-accent-rule);color:inherit}

/* aspect-ratio rather than a fixed height: the card is 390px wide at 3-up and
   full-width on a phone, and one fixed height cannot serve both without
   letterboxing. object-fit:cover absorbs any source ratio — which matters more
   here than on the blog, because these archives mix post types and nobody has
   ever curated their thumbnails. The same box governs the hatch fallback
   (dxr_hatch is called with height => 0, so it emits no --hNNN class), which is
   what keeps every card in a row the same height whether or not the post has a
   featured image. */
.dxr-page-archive .dxr-arch__media{
  aspect-ratio:16/9;
  flex-shrink:0;
  overflow:hidden;
}
/* The hatch fallback composes `.dxr-arch__media .dxr-hatch` on ONE element, and
   this two-class selector outranks the single-class .dxr-hatch (components §9),
   so a solid background here would silently swallow the diagonal-hatch
   placeholder. Same trap, same fix, as .dxr-panel__media in dxr-components.css
   §12: the fill applies only when the hatch is absent; the box metrics above
   stay unconditional. */
.dxr-page-archive .dxr-arch__media:not(.dxr-hatch){background:var(--dxr-surface-raised)}
.dxr-page-archive .dxr-arch__media img{display:block;width:100%;height:100%;object-fit:cover}

.dxr-page-archive .dxr-arch__card-body{
  display:flex;flex-direction:column;flex:1;
  padding:20px;
}

/* Post-type kicker. Rendered only on author and date archives, which are the
   only two that can genuinely mix post types — see archive.php. Mono, because
   it is a label; the shared .dxr-label--strip role is not reused because that
   one carries its own margins for a card header, which this is not.
   align-self:flex-start is load-bearing, not tidiness: the body is a flex
   COLUMN whose default align-items:stretch would blow this span to the full
   card width, which would surface the moment anything gave it a background. */
/* Matches .dxr-list__card-term on the search/use-cases/videos cards:
   same slot, same purpose, so same letter-spacing and colour. */
.dxr-page-archive .dxr-arch__card-kicker{
  align-self:flex-start;
  margin-bottom:10px;
  font:500 10px/1 var(--dxr-font-mono);
  letter-spacing:.1em;
  text-transform:uppercase;
  color:var(--dxr-accent-text);
}

.dxr-page-archive .dxr-arch__card-title{margin:0 0 8px}

/* WordPress auto-excerpts run to 55 words and would leave card heights wildly
   unequal. Bounded VISUALLY — the copy itself is never rewritten or truncated
   server-side. */
.dxr-page-archive .dxr-arch__card-excerpt{
  margin:0;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;
  overflow:hidden;
}

/* Mono, because everything in it is measured: a name and a date. margin-top:auto
   pins the row to the card's bottom edge, so cards of unequal copy still line
   their meta rules up across a row. */
.dxr-page-archive .dxr-arch__card-meta{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin-top:auto;padding-top:16px;
  border-top:1px solid var(--dxr-border-inner);
  font:400 11px/1.5 var(--dxr-font-mono);
  color:var(--dxr-text-subtle);
}
.dxr-page-archive .dxr-arch__card-meta time{font-variant-numeric:tabular-nums}
.dxr-page-archive .dxr-arch__card-sep{color:var(--dxr-border-strong)}


/* ==========================================================================
   §5 Pagination — derived, not in the prototype

   Derivation: the number cell IS the prototype's filter chip (line 649), and the
   chip's selected state IS the current page — the one "selected" idiom the
   design owns. Figures stay mono because they are measured; the prev/next labels
   are words, so they drop to sans. Left-aligned, because every band in this
   design aligns to the container's left edge and a centred element would be the
   only centred thing on the page.

   The class names are paginate_links()' own output, unchanged, so the emitted
   DOM matches every other list page in the redesign.
   ========================================================================== */
.dxr-page-archive .dxr-arch__pager{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin-top:48px;padding-top:28px;
  border-top:1px solid var(--dxr-border);
}
.dxr-page-archive .dxr-arch__pager .page-numbers{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:var(--dxr-arch-page-h);height:var(--dxr-arch-page-h);padding:0 12px;
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-radius-md);
  background:var(--dxr-surface);
  color:var(--dxr-ink);
  font:500 13px/1 var(--dxr-font-mono);
  transition:border-color .15s ease,color .15s ease;
}
.dxr-page-archive .dxr-arch__pager a.page-numbers:hover{
  border-color:var(--dxr-accent-rule);color:var(--dxr-accent-text);
}
.dxr-page-archive .dxr-arch__pager .page-numbers.current{
  background:var(--dxr-ink);border-color:var(--dxr-ink);color:var(--dxr-on-dark);
}
/* prev/next carry prose ("Next »"), so they leave the mono role. */
.dxr-page-archive .dxr-arch__pager .page-numbers.prev,
.dxr-page-archive .dxr-arch__pager .page-numbers.next{
  padding:0 16px;font:600 13px/1 var(--dxr-font-sans);
}
.dxr-page-archive .dxr-arch__pager .page-numbers.dots{
  min-width:auto;padding:0 4px;
  border-color:transparent;background:transparent;
  color:var(--dxr-text-subtle);
}


/* ==========================================================================
   §6 Empty state — derived; the parent template has none

   More reachable here than on any curated list page: an author with no
   published posts, a term whose only post was unpublished, a date archive that
   outlives its posts.
   ========================================================================== */
.dxr-page-archive .dxr-arch__empty{
  /* No top margin: the count line is always suppressed when this renders (there
     are zero results to count), so nothing precedes it inside the band and
     --dxr-section-y is the whole opening rhythm. See the note in §4. */
  max-width:min(100%,620px);
  background:var(--dxr-surface);
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-radius-panel);
  padding:var(--dxr-pad-panel);
}
/* The 44px hit area for the recovery link already comes from the shared
   .dxr-cta-link::after{inset:-16px 0} in dxr-components.css — padding it again
   here would stack a second overlay reaching up into the paragraph above, which
   is the exact regression dxr-page-blog.css §6 records. Prototype margin only. */
.dxr-page-archive .dxr-arch__empty-text{margin:8px 0 20px}
