/* ==========================================================================
   3DOptix redesign — Resources (Academy) index, page-unique CSS.

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

   Design source: the approved prototype, '3DOptix Website.dc.html' lines
   628-743 (screen "Academy index"), plus README §6. Every "proto NNN" below
   points at that block.

   THE ONE PLACEMENT DECISION, stated up front.
   The prototype draws the search field and the category chips on the SUNKEN
   band (line 644), one band below the dark header. README §6 — and the brief —
   put them INSIDE the dark band. The README is followed: the whole control
   surface (breadcrumb, H1, lede, search, filters) is one dark header, and the
   sunken band below is purely results. The controls keep the prototype's
   geometry to the pixel; only their colour ROLES invert, and every inverted
   value is an existing on-dark token (§1.5 of dxr-tokens.css) rather than a new
   colour. See §2 for the two places that inversion is not mechanical.

   RULES FOR THIS FILE:
   - SCOPE. Every selector is scoped to .dxr-page-resources, the wrapper class
     the template emits. Legacy Elementor / Academy article / WooCommerce markup
     keeps its own bullets, paragraph spacing and link underlines. No bare
     element selectors, ever, and nothing here may leak to a sibling page —
     other agents are writing sibling templates in parallel.
   - No new colour. Every value resolves from the token layer; the only raw
     numbers are geometry transcribed from the prototype, and each one is named
     in §0 rather than repeated as a literal below.
   - No new keyframe. The only motion is a border/colour transition, already
     neutralised by the shared prefers-reduced-motion block (dxr-components.css
     §2).
   - The spectrum gradient appears ZERO times in this file. The site-wide budget
     stays at exactly two placements: the nav's 2px and the footer's 3px.
   - One media query, at one breakpoint, for one property — see §2.3.

   Contents
     §0  Page-local custom properties
     §1  Header band — dark
     §2  Controls — search field and category chips, on dark
     §3  Results line
     §4  Card grid and card
     §5  Pagination
     §6  Empty state
     §7  "Other resources" panel
   ========================================================================== */


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

   Prototype values with no entry in the token layer.
   ========================================================================== */
.dxr-page-resources{
  --dxr-res-head-top:clamp(27px,3.3vw,44px);   /* proto 632 */
  --dxr-res-head-bot:clamp(32px,3.9vw,52px);   /* proto 632 */
  --dxr-res-field-h:52px;                      /* proto 645 */
  --dxr-res-field-w:min(100%,720px);           /* proto 645 */
  --dxr-res-gap:24px;                          /* proto 662 — NOT --dxr-gap-panels (20px) */
  --dxr-res-media-h:172px;                     /* proto 664 — and .dxr-hatch--h172's documented use */
  --dxr-res-chip-r:6px;                        /* proto 653 — deliberately off the radius scale */
  --dxr-res-page-h:44px;                       /* pagination cell. 44px is the touch floor, matching the blog/use-cases/videos pagers. */
  --dxr-res-mobile:767px;                      /* documented in §2.3; not usable in @media, see there */
}


/* ==========================================================================
   §1 Header band — dark, 64px blueprint (proto 630-641)

   Deliberately NOT .dxr-hero: no glow, no CTA row, no spectrum eyebrow bar. An
   index is a directory, not a pitch. The 64px blueprint cell 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 without !important.
   ========================================================================== */
.dxr-page-resources .dxr-res__head{
  padding:var(--dxr-res-head-top) 0 var(--dxr-res-head-bot);
}

/* The breadcrumb occupies the eyebrow slot — it is already mono, and it is real
   existing content on this page (legacy lines 90-92). That is why dxr_eyebrow()
   is not called. Two classes beat .dxr-section--dark a (0,1,1). */
.dxr-page-resources .dxr-res__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-resources .dxr-res__crumbs a{position:relative;color:var(--dxr-on-dark-body-alt)}
/* The crumb row is 12px mono, so the link's own hit area is ~12px tall. The
   overlay lifts it to 44px without changing the row's height. */
.dxr-page-resources .dxr-res__crumbs a::after{
  content:"";position:absolute;inset:-16px -4px;
}
.dxr-page-resources .dxr-res__crumbs a:hover{color:var(--dxr-on-dark)}

/* Proto 636. Smaller than .dxr-h1--page on purpose — an index H1 is not a
   product H1 — and looser in the line than .dxr-h1--compact. 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. If a second index ever needs it, promote
   it there rather than copying it a third time. */
.dxr-page-resources .dxr-res__title{
  margin:0 0 14px;
  font:800 clamp(27px,4.2vw,46px)/1.08 var(--dxr-font-sans);
  letter-spacing:-.038em;
  color:var(--dxr-on-dark);
}

/* Proto 637. */
.dxr-page-resources .dxr-res__lede{
  margin:0;
  max-width:min(100%,620px);
  font:400 16px/1.7 var(--dxr-font-sans);
  color:var(--dxr-on-dark-secondary);
}


/* ==========================================================================
   §2 Controls — search field and category chips, ON DARK (proto 643-655)

   §2.1 THE FIELD.
   Geometry is the prototype's, unchanged: 52px tall, capped at 720px, 8px
   radius, 18px input padding, and a flush-mounted submit at 0 26px in
   700 13px/1 uppercase with .05em tracking. Only the fill, the border and the
   text colour move to the on-dark tokens.

   A white field on #0B1220 was the other option and is what the prototype's
   own colours would give. It is not used: at 720px wide it becomes the
   brightest object on the page and outweighs the H1. The translucent form is
   the system's existing on-dark control idiom — --dxr-panel-on-dark is the dark
   PANEL fill and --dxr-btn-border-dark is exactly the border .dxr-btn--ghost-dark
   uses — so the field reads as a control without competing with the heading.
   Reverting is a two-value change if the client prefers the literal prototype.

   The design layer contains NO form-control rules of any kind (no input, form
   or search selector in tokens/components/shell), so the appearance reset below
   is required, not defensive.

   ACCESSIBILITY. The placeholder runs at --dxr-on-dark-secondary (0.62), not at
   the caption 0.50: composited on the field fill it measures ~6.4:1, where 0.50
   lands near 4.6:1. The visible label is sr-only, so the placeholder is doing
   real work and is held to body-text contrast. Focus rings the WRAPPER, because
   the field is one focus surface — the input's own ring is suppressed so the
   two do not double up.
   ========================================================================== */
.dxr-page-resources .dxr-res__search{
  display:flex;align-items:stretch;
  margin-top:26px;
  max-width:var(--dxr-res-field-w);
  height:var(--dxr-res-field-h);
  background:var(--dxr-panel-on-dark);
  border:1px solid var(--dxr-btn-border-dark);
  border-radius:var(--dxr-radius-md);
  overflow:hidden;
}
.dxr-page-resources .dxr-res__search-input{
  flex:1;min-width:0;
  -webkit-appearance:none;appearance:none;
  margin:0;padding:0 18px;
  border:0;background:transparent;
  /* 16px, not the prototype's 15px, and this is a deliberate deviation:
     iOS Safari auto-zooms any focused form control whose font-size is under
     16px, and it does NOT restore the zoom on blur — the visitor is left on a
     ~300px visual viewport with the page scrolled sideways. One pixel of type
     against a stuck zoom on the Academy's primary control is not a trade. */
  font:400 16px/1 var(--dxr-font-sans);
  color:var(--dxr-on-dark);
}
.dxr-page-resources .dxr-res__search-input::placeholder{
  color:var(--dxr-on-dark-secondary);opacity:1;
}
/* Safari's search decorations would sit on the dark fill as a light blob. */
.dxr-page-resources .dxr-res__search-input::-webkit-search-cancel-button{-webkit-appearance:none}
.dxr-page-resources .dxr-res__search-input::-webkit-search-decoration{-webkit-appearance:none}

/* Not .dxr-btn: the prototype's submit is a flush-mounted segment of the field
   with no radius and no independent height, and its 700 13px uppercase is not a
   .dxr-btn size (--nav and --block are 14px, not uppercase). Colour, weight and
   hover still come from the primary-button tokens, so the two stay in step. */
.dxr-page-resources .dxr-res__search-submit{
  -webkit-appearance:none;appearance:none;
  display:inline-flex;align-items:center;white-space:nowrap;
  margin:0;padding:0 26px;border:0;cursor:pointer;
  background:var(--dxr-primary);
  color:var(--dxr-on-dark);
  font:700 13px/1 var(--dxr-font-sans);
  letter-spacing:.05em;text-transform:uppercase;
  transition:background-color .15s ease;
}
.dxr-page-resources .dxr-res__search-submit:hover{background:var(--dxr-primary-hover)}

/* One focus surface, ringed once. */
.dxr-page-resources .dxr-res__search:focus-within{
  border-color:var(--dxr-cyan-light);
  outline:2px solid var(--dxr-cyan-light);
  outline-offset:2px;
}
.dxr-page-resources .dxr-res__search-input:focus-visible{outline:none}

/* --------------------------------------------------------------------------
   §2.2 THE CHIPS (proto 651-655)

   NOT .dxr-chip. That is the mono 500 9px/1 .1em uppercase Popular/Coming-soon
   BADGE (dxr-components.css §7) — a static label. These are sans 600 13px
   filter CONTROLS with an active state. Different component, different name;
   reusing the badge class would have coupled two unrelated things.

   THE INVERSION. The prototype's active chip is an INK fill with white text on
   a light ground (line 652). On #0B1220 that state disappears. So the pair is
   inverted the way the system already inverts a filled control on dark — the
   .dxr-btn--inverse idiom: active becomes a WHITE fill with ink text, inactive
   becomes transparent with the ghost-dark border. Contrast in both states is
   the maximum the palette offers.

   Every chip carries a 1px border, including the active one, so all three sit
   at the same height regardless of state (the prototype's active chip declares
   no border and would be 2px shorter).

   The prototype's closing hairline under the chip row (line 651) is dropped:
   the row is now the last thing in the dark band, and the band edge already
   draws that boundary. A rule there would be a second line 28px above the first.
   -------------------------------------------------------------------------- */
.dxr-page-resources .dxr-res__chips{
  display:flex;gap:10px;flex-wrap:wrap;
  margin-top:24px;
}
.dxr-page-resources .dxr-res__chip{
  position:relative;
  padding:9px 16px;
  border:1px solid var(--dxr-btn-border-dark);
  border-radius:var(--dxr-res-chip-r);
  background:transparent;
  color:var(--dxr-on-dark-body);
  font:600 13px/1 var(--dxr-font-sans);
  transition:background-color .15s ease,border-color .15s ease,color .15s ease;
}
/* Touch target. The chip box is 9+13+9+2 = 33px, 11px under the 44px floor, and
   the page renders a whole row of them. The overlay grows the hit area to 45px
   without moving any geometry; 6px of bleed stays inside the 10px chips gap. */
.dxr-page-resources .dxr-res__chip::after{
  content:"";position:absolute;inset:-6px 0;
}
.dxr-page-resources .dxr-res__chip:hover{
  border-color:var(--dxr-btn-border-dark-hover);
  color:var(--dxr-on-dark);
}
.dxr-page-resources .dxr-res__chip--active,
.dxr-page-resources .dxr-res__chip--active:hover{
  background:var(--dxr-surface);
  border-color:var(--dxr-surface);
  color:var(--dxr-ink);
}

/* --------------------------------------------------------------------------
   §2.3 THE MOBILE LABEL — the legacy behaviour, one text node

   Legacy prints every term name twice: a .desktop span with "General Tutorials"
   and a .mobile span with "General", showing one or the other by CSS. Here the
   name is split in the template into a head and a trailing " Tutorials" tail,
   and only the tail is hidden — no duplicated text in the accessibility tree,
   no duplicated text in the copy buffer. The anchor's aria-label carries the
   FULL name at every width, so the accessible name never changes with the
   viewport.

   THE BREAKPOINT. 767px is transcribed, not invented: it is the legacy
   stylesheet's own mobile breakpoint (style.css line 1937, `@media
   (max-width:767px)`) and the same threshold the legacy inline script used
   (`window.innerWidth < 768`). It is also the ONLY media query in this file.
   The design's "one breakpoint" rule concerns the nav's 900px JS breakpoint —
   no JavaScript is added here, and no layout changes at 767px; exactly one span
   stops rendering.

   The literal must appear here rather than as var(--dxr-res-mobile): a custom
   property cannot be used in a media query condition. The token above exists so
   the number is documented next to the rest of the page's geometry.
   -------------------------------------------------------------------------- */
@media (max-width:767px){
  .dxr-page-resources .dxr-res__chip-tail{display:none}
}


/* ==========================================================================
   §3 Results line (proto 657-660)

   Legacy prints one sentence — `Results for <Category> (7)`. The design splits
   the same two facts into a heading and a mono count. Mono is in policy: a
   count is measured content, which is exactly the split the two-font rule draws.

   The heading role is NEW: the nearest shared role, .dxr-h3-product, runs /1.16
   at -.03em where line 658 is /1.2 at -.028em. Close enough to look identical
   and far enough that transcribing it is honest.

   NO padding override on .dxr-res__body, unlike the header band. The prototype
   opens the sunken band on the tight clamp(27px,3.3vw,44px) because the band
   starts with the search field — a control that belongs against the header it
   filters. With the controls moved up into the dark band (see the note at the
   top of this file), the sunken band now opens on the results heading, which is
   a section start and takes the system's standard --dxr-section-y. That is
   .dxr-section's own value, so nothing is declared here.
   ========================================================================== */
.dxr-page-resources .dxr-res__results{
  display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  margin:0 0 22px;
}
.dxr-page-resources .dxr-res__results-title{
  margin:0;
  font:800 clamp(19px,2.2vw,24px)/1.2 var(--dxr-font-sans);
  letter-spacing:-.028em;
  color:var(--dxr-ink);
}
/* 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-resources .dxr-res__count{
  font:400 13px/1 var(--dxr-font-mono);
  color:var(--dxr-text-subtle);
  font-variant-numeric:tabular-nums;
}


/* ==========================================================================
   §4 Card grid and card (proto 662-676)

   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 legacy page size of 12 therefore fills four clean
   rows of three with no ragged tail.

   The card is SHAPED like .dxr-panel but is not one — no cap rule, 172px media
   instead of 180px, a flat 20px body instead of --dxr-pad-panel-body, and the
   whole card is one <a>. Built as its own component rather than forced through
   dxr_panel_cap().
   ========================================================================== */
.dxr-page-resources .dxr-res__grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--dxr-min-3up)),1fr));
  gap:var(--dxr-res-gap);
}

/* Proto 663: bordered, 12px radius, white fill so the card lifts off the sunken
   ground. Hover moves the BORDER (and the title) only — the system owns exactly
   three shadows and none of them is a card shadow, so no lift and no scale. */
.dxr-page-resources .dxr-res__card{
  display:flex;flex-direction:column;
  background:var(--dxr-surface);
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-radius-panel);
  overflow:hidden;
  color:inherit;
  transition:border-color .15s ease;
}
.dxr-page-resources .dxr-res__card:hover{border-color:var(--dxr-accent-rule);color:inherit}
.dxr-page-resources .dxr-res__card:hover .dxr-res__card-title{color:var(--dxr-accent-text)}

/* Proto 664: a fixed 172px band, the height dxr-components.css §9 already
   reserves for tutorial cards (.dxr-hatch--h172, "172 tutorial cards").
   object-fit:cover absorbs any source ratio — the library's featured images are
   not uniform — and the SAME box governs the hatch fallback, which is why
   dxr_hatch() is called with height => 0: no --hNNN class is emitted, so the
   height below is the only one in play and every card in a row matches whether
   or not the post has a featured image. */
.dxr-page-resources .dxr-res__media{
  height:var(--dxr-res-media-h);
  flex-shrink:0;
  overflow:hidden;
}
/* The hatch fallback composes `.dxr-res__media .dxr-hatch` on ONE element, and
   this two-class selector outranks the single-class .dxr-hatch, 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 is
   applied only when the hatch is absent; the box metrics above stay
   unconditional. */
.dxr-page-resources .dxr-res__media:not(.dxr-hatch){background:var(--dxr-surface-raised)}
.dxr-page-resources .dxr-res__media img{display:block;width:100%;height:100%;object-fit:cover}

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

/* Proto 668. A NEW mono role: .dxr-label is .14em on --dxr-text-subtle, this is
   .1em on the page accent. Mono is in policy — it is a taxonomy key, not prose. */
.dxr-page-resources .dxr-res__card-kicker{
  margin-bottom:10px;
  font:500 10px/1 var(--dxr-font-mono);
  letter-spacing:.1em;text-transform:uppercase;
  color:var(--dxr-accent-text);
}

/* The title reuses the shared .dxr-panel-title (700 18px/1.3, -.02em, ink) —
   an exact match for proto 669. Only the margin and the hover transition are
   local. */
.dxr-page-resources .dxr-res__card-title{margin:0 0 8px;transition:color .15s ease}

/* Proto 670 is 14px/1.6; the shared .dxr-body-sm is 14px/1.65 on the same
   colour. .dxr-body-sm is used and the leading is not forked for 0.05.
   WordPress auto-excerpts run long and would leave card heights wildly
   unequal, so the copy is bounded VISUALLY — never rewritten or truncated
   server-side. margin-top:auto pins it to the bottom of unequal cards. */
.dxr-page-resources .dxr-res__card-excerpt{
  margin:0;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;
  overflow:hidden;
}


/* ==========================================================================
   §5 Pagination — derived, not in the prototype (legacy lines 192-202)

   Derivation: the number cell IS the filter chip (proto 653), and the chip's
   selected state IS the current page — the one "selected" idiom this 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 pager would be the only
   centred thing on the page.

   The class names are paginate_links()' own output, unchanged, so the emitted
   DOM stays identical to production's.
   ========================================================================== */
.dxr-page-resources .dxr-res__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-resources .dxr-res__pager .page-numbers{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:var(--dxr-res-page-h);height:var(--dxr-res-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);
  font-variant-numeric:tabular-nums;
  transition:border-color .15s ease,color .15s ease;
}
.dxr-page-resources .dxr-res__pager a.page-numbers:hover{
  border-color:var(--dxr-accent-rule);color:var(--dxr-accent-text);
}
.dxr-page-resources .dxr-res__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-resources .dxr-res__pager .page-numbers.prev,
.dxr-page-resources .dxr-res__pager .page-numbers.next{
  padding:0 16px;font:600 13px/1 var(--dxr-font-sans);
}
.dxr-page-resources .dxr-res__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 legacy template has none

   Two reachable cases: a search with no hits, and a category with no posts
   (get_terms runs hide_empty => false, so a chip can lead to one). Legacy
   renders an empty div for both. Panel geometry is the shared one, so the empty
   state reads as a card in the same family as the results it replaces.
   ========================================================================== */
.dxr-page-resources .dxr-res__empty{
  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);
}
.dxr-page-resources .dxr-res__empty-text{margin:8px 0 20px}


/* ==========================================================================
   §7 "Other resources" panel (proto 679-690)

   A bordered white panel INSIDE the sunken band — deliberately not
   dxr_cta_band(), which is a full-bleed section and would close the page on a
   conversion band the prototype does not have.

   Proto 686-688 give 46px / 0 22px buttons. No .dxr-btn size matches: --md is
   48px / 0 24px and --block is 46px but width:100%. The variant supplies every
   colour, border and hover; only the two size values are corrected locally, so
   the buttons still track any change to the secondary variant.
   ========================================================================== */
.dxr-page-resources .dxr-res__otherres{
  margin-top:56px;
  display:flex;align-items:center;justify-content:space-between;
  gap:40px;flex-wrap:wrap;
  background:var(--dxr-surface);
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-radius-panel);
  padding:34px 36px;
}
.dxr-page-resources .dxr-res__otherres-copy{max-width:min(100%,620px)}
.dxr-page-resources .dxr-res__otherres-title{
  margin:0 0 8px;
  font:800 22px/1.25 var(--dxr-font-sans);
  letter-spacing:-.026em;
  color:var(--dxr-ink);
}
.dxr-page-resources .dxr-res__otherres-text{margin:0}
.dxr-page-resources .dxr-res__otherres-actions .dxr-btn{height:46px;padding:0 22px}
