/* ==========================================================================
   3DOptix redesign — /videos index page-unique CSS.

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

   The design does not specify this page. Everything here is derived from the
   ONE collection view the approved prototype contains — the Academy index,
   '3DOptix Website.dc.html' lines 628-741 — so the three index pages read as
   one system. Line references below point at that block.

   RULES FOR THIS FILE:
   - EVERY selector is scoped to .dxr-page-videos, the wrapper class emitted by
     this template alone. Legacy Elementor / blog / Academy / WooCommerce markup
     keeps its own list bullets, paragraph spacing and link underlines. No bare
     element selectors, ever, and the reset's scope is never widened.
   - The .dxr-list__* element names are shared with the sibling index templates
     on purpose, so the three pages stay one component. Only this file's
     .dxr-page-videos scope ships here.
   - No new colour. The only raw numbers are geometry transcribed verbatim from
     the prototype, and each is named in §0 rather than repeated inline.
   - No new keyframe. The three that exist are enough; 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. It stays at exactly
     two site-wide instances: 2px under the nav, 3px atop the footer.
   ========================================================================== */

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

   Prototype values with no entry in the token layer, named once here instead of
   repeated as literals below — same convention as dxr-page-technology.css §0.
   ========================================================================== */
.dxr-page-videos{
  --dxr-list-head-top:clamp(27px,3.3vw,44px);   /* proto 632 */
  --dxr-list-head-bot:clamp(32px,3.9vw,52px);   /* proto 632 */
  --dxr-list-gap:24px;                          /* proto 659 — NOT --dxr-gap-panels (20px) */
  --dxr-list-chip-radius:6px;                   /* proto 649 — between --dxr-radius-badge and --pill */
  --dxr-list-field-h:52px;                      /* proto 643 */

  /* GRID MINIMUM — 240px, the tuned 4-up value. This is the densest of the
     three indexes and the reason is the card, not the page: the video card is a
     16:9 thumbnail plus one title line and nothing else (REST confirms
     excerpt.rendered is empty on every video, because the post body is an embed
     with no prose). Usable width at the 1300px container is 1300 - 2*40 =
     1220px with 24px gaps, so 240px resolves to 4 x 287px (5 would need
     5*240 + 4*24 = 1296 > 1220). At the Blog/Use-Cases 320px/3-up the same card
     would be 390 wide by ~250 tall with 60% of its area a single line of text —
     visibly under-filled, and it would read as a different, emptier component
     rather than the same one at higher density. At 287px the thumbnail is 161px
     and the padded title block ~70px, so the card lands at ~250px: a balanced
     block. --dxr-min-4up is documented in dxr-tokens.css as the minimum for
     exactly this class of short, label-like cell, and the 18-per-page setting
     the client already chose is the density signal the minimum follows.

     The 18/4 remainder leaves 2 orphans in the last row. Cosmetic and
     invisible: unlike .dxr-hgrid this is a plain gap grid on a sunken ground
     with no container tint, so an incomplete row shows nothing but background —
     the phantom-cell problem in dxr-components.css §11 does not apply. If clean
     rows are wanted the lever is posts_per_page (16 or 20), NOT a fourth grid
     minimum; the tuned set stays at three values. */
  --dxr-list-min:var(--dxr-min-4up);
}

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

   Deliberately NOT .dxr-hero: no glow, no CTA row, no spectrum eyebrow bar.
   An index 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, so the
   overlay itself needs no CSS here — only the band's own rhythm, which is a
   prototype value rather than a system value.
   ========================================================================== */
.dxr-page-videos .dxr-list__head{
  padding:0;   /* the inner owns the rhythm, per the prototype's single padding rule */
}
.dxr-page-videos .dxr-list__head-inner{
  padding-top:var(--dxr-list-head-top);
  padding-bottom:var(--dxr-list-head-bot);
}

/* The breadcrumb occupies the eyebrow slot — already mono, and already real
   content on this page. That is why the template calls no dxr_eyebrow(). */
.dxr-page-videos .dxr-list__crumbs{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  font:400 12px/1 var(--dxr-font-mono);
  color:var(--dxr-on-dark-caption);
  margin-bottom:24px;
}
.dxr-page-videos .dxr-list__crumbs a{position:relative;color:var(--dxr-on-dark-body-alt)}
.dxr-page-videos .dxr-list__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. */
.dxr-page-videos .dxr-list__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 dxr-components.css §4. */
.dxr-page-videos .dxr-list__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);
}

/* ==========================================================================
   §2 Controls band — sunken (proto 641-652)
   ========================================================================== */
.dxr-page-videos .dxr-list__body{
  background:var(--dxr-surface-sunken);
  padding:var(--dxr-list-head-top) 0 var(--dxr-section-y);
}

/* --- 2.1 Search field (proto 643-646) -------------------------------------
   The design layer contains NO form-control rules of any kind — dxr-tokens.css,
   dxr-components.css and dxr-shell.css carry no input/form/search selector — so
   the appearance reset below is required, not defensive. */
.dxr-page-videos .dxr-list__search{
  display:flex;align-items:stretch;
  max-width:min(100%,720px);
  height:var(--dxr-list-field-h);
  background:var(--dxr-surface);
  border:1px solid var(--dxr-border-strong);
  border-radius:var(--dxr-radius-md);
  overflow:hidden;
}
.dxr-page-videos .dxr-list__search-input{
  flex:1;min-width:0;
  -webkit-appearance:none;appearance:none;
  margin:0;padding:0 18px;
  border:0;background:transparent;
  /* 16px is a FLOOR, not a design choice: iOS Safari auto-zooms any focused
     form control whose computed font-size is below 16px, and it does not undo
     the zoom on blur — the visitor is left on a 300px visual viewport with 20px
     of the page off-screen to the right. The field is a fixed 52px and the UA
     centres the text, so nothing else moves. */
  font:400 16px/1 var(--dxr-font-sans);
  color:var(--dxr-ink);
}
.dxr-page-videos .dxr-list__search-input::placeholder{
  color:var(--dxr-text-disabled);opacity:1;
}
/* The full placeholder stays at every width. The legacy <768px swap script is
   gone with the rest of the breakpoint-driven behaviour; the field is fluid. */
.dxr-page-videos .dxr-list__search-input::-webkit-search-cancel-button{-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. Colour, weight and hover still come
   from the primary tokens, so the two stay in step. */
.dxr-page-videos .dxr-list__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-videos .dxr-list__search-submit:hover{background:var(--dxr-primary-hover)}

/* --- 2.2 Category filters (proto 648-652) ---------------------------------
   NOT .dxr-chip — that component is the 9px mono Popular / Coming-soon badge.
   These are prose category names, so they are sans, and the active state is the
   ink fill the prototype uses. §5 reuses this exact pair for the current page
   number, which is what makes pagination read as the same family. */
.dxr-page-videos .dxr-list__filters{
  display:flex;gap:10px;flex-wrap:wrap;
  margin-top:24px;padding-bottom:28px;
  border-bottom:1px solid var(--dxr-border);
}
/* TOUCH TARGET. The `font` shorthand sets line-height:1, so the chip's box is
   9 + 13 + 9 + 2 borders = 33px — 11px under the 44px floor. Raising the padding
   would visibly fatten the chip at every width, so the HIT AREA is enlarged
   instead and the 33px geometry is left exactly as transcribed: 33 + 5 + 5 =
   43px, and the 5px of vertical bleed equals half the 10px row gap, so stacked
   rows touch without overlapping. */
.dxr-page-videos .dxr-list__filter{
  position:relative;
  padding:9px 16px;
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-list-chip-radius);
  background:var(--dxr-surface);
  color:var(--dxr-body);
  font:600 13px/1 var(--dxr-font-sans);
  transition:border-color .15s ease,color .15s ease;
}
.dxr-page-videos .dxr-list__filter::after{
  /* -6px, not -5px: the chip box is 9+13+9+2 = 33px, so 33+12 = 45px clears the
     44px touch floor. 6px of vertical bleed still sits inside the 10px filter
     row gap, so stacked rows do not overlap. */
  content:"";position:absolute;inset:-6px 0;
}
.dxr-page-videos .dxr-list__filter:hover{
  border-color:var(--dxr-accent-rule);
  color:var(--dxr-accent-text);
}
.dxr-page-videos .dxr-list__filter.is-active,
.dxr-page-videos .dxr-list__filter.is-active:hover{
  background:var(--dxr-ink);
  border-color:var(--dxr-ink);
  color:var(--dxr-on-dark);
}

/* ==========================================================================
   §3 Results line (proto 654-657)
   ========================================================================== */
.dxr-page-videos .dxr-list__results{
  display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  margin:36px 0 22px;
}
/* The heading echoes the visitor's raw ?find_academy= query. An unbroken
   40-character token at the clamp minimum (19px/800) measures ~418px against the
   280px container at a 320px viewport, and nothing in the ancestor chain clips
   or scrolls — the document itself would scroll sideways. `anywhere` only
   engages when the word genuinely does not fit, so ordinary terms are
   unaffected. */
.dxr-page-videos .dxr-list__results .dxr-h3-product{overflow-wrap:anywhere}
/* 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-videos .dxr-list__count{
  font:400 13px/1 var(--dxr-font-mono);
  color:var(--dxr-text-subtle);
}

/* ==========================================================================
   §4 Card grid + card (proto 659-726)
   ========================================================================== */
.dxr-page-videos .dxr-list__grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--dxr-list-min)),1fr));
  gap:var(--dxr-list-gap);
}

/* No card background — see dxr-page-usecases.css: the prototype's cards are
   transparent on the sunken band. */
.dxr-page-videos .dxr-list__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;
}
/* Border only. The system has three shadows and none of them is a card shadow,
   so no lift and no scale. */
.dxr-page-videos .dxr-list__card:hover{
  border-color:var(--dxr-accent-rule);
  color:inherit;
}

/* aspect-ratio rather than the fixed --dxr-hatch--h172 the prototype's tutorial
   card uses: at 4-up this card is ~287px wide, and a 172px fixed height would
   letterbox a 16:9 source. object-fit:cover absorbs any ratio; the production
   thumbnails are already 379x215. The same rule serves the hatch fallback,
   which is why the template passes 'height' => 0 (no --hNNN class). */
.dxr-page-videos .dxr-list__media{
  aspect-ratio:16/9;
  flex-shrink:0;
  overflow:hidden;
}
/* The :not() is load-bearing: dxr_hatch() puts .dxr-hatch on the SAME div as
   .dxr-list__media, so a flat background here paints over the hatch gradient
   and the placeholder disappears. Matches the two sibling list pages. */
.dxr-page-videos .dxr-list__media:not(.dxr-hatch){background:var(--dxr-surface-raised)}
.dxr-page-videos .dxr-list__media img{
  display:block;width:100%;height:100%;object-fit:cover;
}

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

/* Mono, uppercase, accent — a taxonomy label is measured content, not prose.
   Rendered only on a search, where results span categories (see the template). */
.dxr-page-videos .dxr-list__card-term{
  display:block;margin-bottom:10px;
  font:500 10px/1 var(--dxr-font-mono);
  letter-spacing:.1em;text-transform:uppercase;
  color:var(--dxr-accent-text);
}

.dxr-page-videos .dxr-list__card-title{margin:0}

/* An excerpt is empty on every production video, so this rule normally never
   applies. When one exists it is bounded VISUALLY — the copy itself is never
   rewritten or truncated server-side. */
.dxr-page-videos .dxr-list__card-excerpt{
  margin:8px 0 0;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;
  overflow:hidden;
}

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

   Derivation: the number cell IS the filter chip of §2.2, and the chip's
   selected state IS the current page. That is the only "selected" idiom the
   design owns, so filters and pagination read as one family. 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 selectors below target paginate_links()' own class names, which is why
   they are the one place this file does not use a dxr- class — they are still
   fully scoped, both to .dxr-page-videos and to .dxr-list__pager.
   ========================================================================== */
.dxr-page-videos .dxr-list__pager{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin-top:48px;padding-top:28px;
  border-top:1px solid var(--dxr-border);
}
/* 44px, not 40: the cell is a touch target and, as the derivation above says,
   the prototype transcribes no value for it. */
.dxr-page-videos .dxr-list__pager .page-numbers{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;height:44px;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-videos .dxr-list__pager a.page-numbers:hover{
  border-color:var(--dxr-accent-rule);
  color:var(--dxr-accent-text);
}
.dxr-page-videos .dxr-list__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-videos .dxr-list__pager .page-numbers.prev,
.dxr-page-videos .dxr-list__pager .page-numbers.next{
  padding:0 16px;
  font:600 13px/1 var(--dxr-font-sans);
}
.dxr-page-videos .dxr-list__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
   ========================================================================== */
.dxr-page-videos .dxr-list__empty{
  background:var(--dxr-surface);
  border:1px solid var(--dxr-border);
  border-radius:var(--dxr-radius-panel);
  padding:var(--dxr-pad-panel);
  max-width:min(100%,620px);
}
.dxr-page-videos .dxr-list__empty-title{margin:18px 0 0}
/* TOUCH TARGET. The recovery link is the only way out of a zero-result search
   and the shared .dxr-cta-link is a 14px line box. It is padded HERE rather than
   in dxr-components.css because that primitive is shared with pages other agents
   own. 14 + 15 + 15 = 44px. The paragraph's closing margin drops from 20 to 5 so
   the new padding restores, not adds to, the prototype's 20px gap, and the
   negative bottom margin keeps the panel's own padding symmetrical. */
/* The 44px hit area for this link already comes from the shared
   .dxr-cta-link::after{inset:-16px 0} in dxr-components.css. Adding padding
   here stacked a second overlay 31px tall, which reached up into the
   paragraph above. Prototype margin restored instead. */
.dxr-page-videos .dxr-list__empty-text{margin:8px 0 20px}
