/*
Theme Name: code-raunartisan
Template: bricks
*/

/*
 * style.css — STATIC DESIGN, loaded EVERYWHERE (live front-end + Bricks editor).
 * Keep only design that should be visible while building: theme tokens, fonts,
 * typography, base layout, scrollbar.
 *
 * All animation-related CSS (initial hidden/dimmed states + motion effects) lives
 * in animations.css, which is loaded FRONT-END ONLY (see functions.php) so the
 * editor isn't full of invisible elements. See Instructions.md → "animations.css".
 */

/* ─── Design tokens ──────────────────────────────────────────────────────────
 * The re-skin surface. On a new project, override these and the whole animation
 * stack follows — no JS edits. Defined here (not animations.css) so they resolve
 * in the Bricks editor too.
 *
 * Tokens marked (JS) are read at runtime by scripts via RAnim.cssVar() /
 * RAnim.cssVarNum() — see js/core/utils.js. If you delete one, the script falls
 * back to the same literal, so nothing breaks; it just stops being themeable.
 *
 * NOT tokenizable: the 768px mobile breakpoint. CSS custom properties don't work
 * inside @media queries, so it lives in exactly two places — BREAKPOINT in
 * js/core/utils.js and the @media rules in animations.css. Change both together.
 * ------------------------------------------------------------------------- */

:root {
    /* Surfaces */
    --ra-surface:          #0d0d0d;   /* card/page base — guide-index fade, gallery gradient */
    --ra-surface-rgb:      13, 13, 13; /* same colour as an RGB triplet, for rgba(var(--x), a) */
    --ra-surface-black:    #000000;   /* true black — overlays, mobile header background */
    --ra-surface-overlay:  #010202;   /* depth-gallery / image-fade injected overlay */
    --ra-hairline:         #1a1a1a;   /* 1px separators */

    /* Scrims — black at alpha, layered over content */
    --ra-scrim-index:      rgba(0, 0, 0, 0.8);   /* guide-index backdrop */
    --ra-scrim-card:       rgba(0, 0, 0, 0.7);   /* testimonial hover-dim */
    --ra-scrim-menu:       rgba(0, 0, 0, 0.3);   /* mobile-menu backdrop */

    /* Glows */
    --ra-glow-rest:        rgba(255, 255, 255, 0.1);
    --ra-glow-hover:       rgba(255, 255, 255, 0.4);

    /* Text */
    --ra-text-base:        #ffffff;
    --ra-text-accent:      #bfacfb;
    --ra-gradient-text:    linear-gradient(90deg, #99ccff, #d966ff, #ff4d4d);  /* (JS) load-blur-words */

    /* hud-card — 1px frame + a square marker centred on each corner */
    --ra-hud-border:       rgba(255,255,255,0.05);   /* the card's 1px frame */
    --ra-hud-marker:       #262626;   /* the four corner squares — independent of the frame */
    --ra-hud-border-width: 1px;
    --ra-hud-marker-size:  7px;

    /* card-bg-blur — frosted backdrop behind a card */
    --ra-card-blur:        24px;

    /* scrub-border — the full-screen expanding box */
    --ra-border-bg-start:  rgba(0, 0, 0, 0.5);   /* (JS) frosted start */
    --ra-border-bg-end:    rgba(0, 0, 0, 1);     /* (JS) opaque end */
    --ra-border-radius:    16px;                 /* (JS) top corner radius at rest */
    --ra-border-blur:      16px;                 /* constant backdrop-filter blur */

    /* drag-canvas — how much larger the media renders than its crop box.
       ONE number, read by BOTH halves of the crop: the `scale` in animations.css
       (which covers the pre-JS window) and drag-canvas.js (which owns it after).
       It also DEFINES the parallax travel budget — the overhang per side is
       (scale - 1) / 2 of the box, and content may never travel further than that
       or a cropped edge slides into view. Raise it for a stronger parallax. */
    --ra-canvas-scale:     1.25;                 /* (JS) 1.25 → 10% of the media hidden per side */

    /* drag-scroller — the same idea on one axis, for a row's per-item parallax.
       Read by the `scale` in animations.css and by drag-scroller.js, and it equally
       defines that parallax's travel budget. Only in play where an item carries a
       .drag-content and the row sets data-parallax. */
    --ra-scroller-scale:   1.4;                  /* (JS) 1.2 → 10% of the media hidden per side */

    /* work-showcase — the thumbnail strip over each card's image.
       The size is read by JS too (it becomes the thumbnails' `sizes` attribute, so a
       small slot fetches a small candidate rather than the stage-sized one Bricks
       would ask for), which is why it lives here rather than being typed in twice. */
    --ra-showcase-thumb:        40px;            /* (JS) thumbnail box — width; the ratio makes it square */
    --ra-showcase-thumb-rest:   0.55;            /* opacity of a thumbnail that isn't the shot on show */
}

/* ─── Typography ─────────────────────────────────────────────────────────── */

.guide-text-purple {
    color: var(--ra-text-accent);
}

.guide-text-white {
    color: var(--ra-text-base);
}

.highlighted {
    font-family: 'Playfair Display', serif;
    font-style: italic;
    font-size: 48px;
}

.recoleta {
    font-family: 'recoleta';
    font-style: italic;
    font-weight: 400;
}

.recoleta-l {
    font-family: 'recoleta';
    font-weight: 200;
}

/* Stretches the LAST line of text edge-to-edge by widening its word spacing — on a
   single-line heading that's the only line, so the whole thing spans the container.
   For multi-line copy add text-align: justify in Bricks too, otherwise the earlier
   lines keep their normal alignment and only the last one stretches. */
.full-width-text {
    text-align-last: justify;
}

@media (max-width: 1366px) {
    .highlighted {
        font-size: 48px;
    }
}

@media (max-width: 1024px) {
    .highlighted {
        font-size: 48px;
    }
}

@media (max-width: 767px) {
    .highlighted {
        font-size: 8.4vw;
    }
    .project-desc,
    .project-title {
        font-size: 12px !important;
    }
    .project-image-container {
        aspect-ratio: 1 / 1;
    }
}

/* ─── Custom scrollbar (clean / minimal) ─────────────────────────────────── */

/* Reserve the scrollbar gutter at all times so the page doesn't shift horizontally
   when scroll unlocks after the hero entrance and the thumb reappears. During the
   lock (Lenis sets overflow:hidden) the gutter stays reserved but no thumb shows;
   the thumb only appears once scrolling is re-enabled. */
html {
    scrollbar-gutter: stable;
}

/* WebKit — Chrome, Edge, Safari */
::-webkit-scrollbar {
    width: 12px;
    height: 12px;              /* horizontal scrollbars too */
}
::-webkit-scrollbar-track {
    background: var(--ra-hairline);
}
::-webkit-scrollbar-thumb {
    background: var(--ra-surface-black);
    border-radius: 999px;      /* fully rounded thumb */
}
::-webkit-scrollbar-thumb:hover {
    background: #e6e6e6;       /* subtle darken on hover for discoverability */
}

/* Firefox (no thumb border-radius support; uses thin track) */
html {
    scrollbar-width: thin;
    scrollbar-color: var(--ra-surface-black) var(--ra-hairline);   /* thumb, track */
}

/* ─── .icon-box-big vignette overlay ─────────────────────────────────────── */

/* Required so the absolutely-positioned ::before (inset:0) anchors to the box itself
   rather than some other positioned ancestor. */
.icon-box-big {
    position: relative;
}

.icon-box-big::before {
    content: "";
    position: absolute;
    /* top is pushed up above the card so the white top glow band lands in the area the
       container clips (overflow:hidden) — hides the top-edge artifact. left/right/bottom = 0.
       -20px ≥ the 16px blur, so the top glow fully fades before the visible top edge. */
    inset: -20px 2px 2px 2px;
    pointer-events: none;
    filter: blur(2px);
    border-radius: 4px;

    /* Inset shadow */
    box-shadow: inset 0 0 14px rgba(255, 255, 255, 1);

    /* Blend mode */
    mix-blend-mode: overlay;
    z-index: 10;
}

.icon-box-big::after {
    content: "";
    position: absolute;
    inset: -20px 0 0 0;
    pointer-events: none;
    border-radius: 4px;

    /* Inset shadow */
    box-shadow: inset 0 0 0px 1px rgba(255, 255, 255, 1);

    /* Blend mode */
    mix-blend-mode: overlay;
    z-index: 11;
}

/* ─── Testimonial card glow (static; hover-dim effect lives in animations.css) ─ */

/* Inset white glow on each carousel card — the card's DEFAULT resting look. Kept on
   disk (not in Bricks) so it's in source control and still shows in the Bricks editor.
   The hover behaviour — hovering one card darkens all the OTHERS with a black overlay —
   is a front-end-only motion effect, so it lives in animations.css. Remove the
   box-shadow from this card in Bricks so this stays the single source of truth. */
.testimonial-card {
    box-shadow: inset 0 0 16px var(--ra-glow-rest);
}

/* ─── .hud-card — 1px frame with a square marker centred on each corner ──── */

/* Static design, so it lives here and shows in the Bricks editor. Frame colour and
   marker colour are separate tokens (--ra-hud-border / --ra-hud-marker) so the squares
   can be an accent while the frame stays hairline-white, or vice versa. */
.hud-card {
    position: relative;   /* containing block for the ::before markers */
    border: var(--ra-hud-border-width) solid var(--ra-hud-border);
}

/* All four squares are ONE pseudo: a box pushed outwards on every side, so its corners
   land on the card's corners — a marker drawn in each of ITS corners is then centred on
   the card corner, half in / half out. Each square is a solid-colour linear-gradient
   "image"; four of them, one per background-position.
   The inset is HALF a marker (to centre it on the corner) PLUS half the border width:
   an absolutely-positioned pseudo offsets from the padding box, i.e. the INNER edge of
   the border, so without that second term the squares would sit a half-border inwards
   and read as off-centre on the stroke.
   Note: the outer half of each square sits OUTSIDE the card, so the card must not have
   overflow:hidden (Bricks: Layout → Overflow) or they'll be clipped to quarter-squares. */
.hud-card::before {
    content: "";
    position: absolute;
    inset: calc((var(--ra-hud-marker-size) + var(--ra-hud-border-width)) / -2);
    pointer-events: none;
    z-index: 1;           /* clears positioned children (image overlays etc.) inside the card */

    background-image:
        linear-gradient(var(--ra-hud-marker), var(--ra-hud-marker)),
        linear-gradient(var(--ra-hud-marker), var(--ra-hud-marker)),
        linear-gradient(var(--ra-hud-marker), var(--ra-hud-marker)),
        linear-gradient(var(--ra-hud-marker), var(--ra-hud-marker));
    background-size: var(--ra-hud-marker-size) var(--ra-hud-marker-size);
    background-position: left top, right top, left bottom, right bottom;
    background-repeat: no-repeat;
}

/* ─── .card-bg-blur — frosted backdrop ───────────────────────────────────── */

/* Blurs whatever sits BEHIND the element, not the element itself (that would be `filter`).
   Standalone and composable — stack it with .hud-card for a frosted HUD panel.
   Two requirements, or the blur is invisible: the element needs a see-through background
   (a fully opaque one in Bricks hides the blurred backdrop completely), and there has to
   be something behind it to sample.
   The -webkit- prefix is still required for Safari/iOS. */
.card-bg-blur {
    backdrop-filter: blur(var(--ra-card-blur));
    -webkit-backdrop-filter: blur(var(--ra-card-blur));
}

/* ─── Guide index card (static look; show/hide + collapse states live in animations.css) ─ */

/* The card is a NON-scrolling FRAME: it clips its content and anchors the full-card fade
   overlay (::after). The inner list (its direct child) is the real scroll area, with its
   scrollbar hidden — so the overlay never scrolls or jumps on expand, and no bar shows.
   This is what lets the overlay be a plain inset:0 pseudo (fills the whole card, inherits
   its height) instead of a fiddly sticky box that misbehaves inside the flex card.
   Give the card a bounded height in Bricks for the scroll to engage. Kept on disk (not
   Bricks per-element CSS) so it's source-controlled and shows in the editor. */
.guide-index-window {
    position: relative;   /* containing block for the ::after overlay */
    overflow: hidden;     /* clip; the card itself does NOT scroll */
}

/* The single scroll area, injected by guide-index.js as the card's only child (it wraps
   whatever module markup you built). Its scrollbar is HIDDEN (still scrollable by wheel /
   touch / drag — data-lenis-prevent on the card covers it). flex:1 + min-height:0 lets it
   fill and shrink inside the flex card; max-height:100% covers a block card — so it scrolls
   either way. It re-creates the card's own vertical stacking for the modules: display:flex +
   column, and gap/align-items inherited from the card so their spacing is preserved.
   overscroll-behavior stops the scroll chaining to the page at the edges. */
.guide-index-scroller {
    display: flex;
    flex-direction: column;
    gap: inherit;                  /* keep the card's row gap between modules */
    align-items: inherit;          /* keep the card's cross-axis alignment */
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    max-height: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;         /* Firefox: hide the scrollbar */
    -ms-overflow-style: none;      /* legacy Edge */
}
.guide-index-scroller::-webkit-scrollbar {
    display: none;                 /* WebKit (Chrome / Edge / Safari): hide the scrollbar */
}

/* Full-card fade overlay, as a pseudo ON the card. inset:0 makes it fill the ENTIRE card and
   inherit its height/width — no hardcoded value needed. It's pinned to the (non-scrolling)
   frame, above the content (z-index 20) and click-through (pointer-events:none). Top→bottom
   gradient: solid --ra-surface for the top 1% then fades out by 8%, transparent through the
   middle, and fades back in from 85% to solid by 99% — softly masking both edges. */
.guide-index-window::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 20;
    pointer-events: none;
    background: linear-gradient(
        to bottom,
        var(--ra-surface) 1%,
        rgba(var(--ra-surface-rgb), 0) 8%,
        rgba(var(--ra-surface-rgb), 0) 85%,
        var(--ra-surface) 99%
    );
}

/* ─── Drag canvas (drag-canvas.js) ───────────────────────────────────────── */

/* STATIC GEOMETRY ONLY — the parts that repeat across every item, so they live on
   disk instead of being re-typed on 40 Bricks elements. Everything that belongs to
   ONE element (the mask's 100dvh + overflow, the plane's 5000×5000 + flex-shrink:0,
   the rows' flex:1 + space-around, each item's WIDTH) stays in Bricks' native
   controls. This block is in style.css, not animations.css, because it's layout the
   Bricks EDITOR must render correctly while you compose the grid.

   The item is the crop box and the content overflows it — the same mask/mover split
   as .drag-canvas / .drag-canvas-plane, one level down. A box can't both clip and
   move its own contents.

   The item takes its HEIGHT from the media's intrinsic ratio (content is in flow at
   width:100%/height:auto), which is what lets you set a width in Bricks and nothing
   else. Consequences worth knowing:
     • Don't give .drag-canvas-content position:absolute — that takes it out of flow
       and the item collapses to zero height.
     • A <video> has NO intrinsic size until its metadata loads (it defaults to
       300×150), so a video item needs an explicit aspect-ratio in Bricks or it will
       render at 2:1 and then jump. Images are fine — Bricks emits width/height. */
/* The plane must be a POSITIONED ancestor, and that is a JS contract, not a look.
   drag-canvas.js measures every item with offsetLeft/offsetTop — the only readings that
   ignore the zoom wrapper's scale — and those are relative to the nearest positioned
   ancestor. With this rule the plane IS that ancestor, so an item's offsetLeft already
   equals its position inside the plane. Drop it (or let Bricks stop setting it) and the
   measurements silently rebase onto some outer element: no error, just parallax offsets
   that are wrong everywhere. */
.drag-canvas-plane {
    position: relative;
}

.drag-canvas-item {
    position: relative;
    overflow: hidden;   /* `clip` instead, if a border-radius leaks in Safari */
    flex: 0 0 auto;     /* never compress: a shrunk item breaks the measured bleed budget */
}
.drag-canvas-content {
    display: block;
    width: 100%;
    height: auto;
}

/* Page chrome, armed by the canvas's own presence so it can't leak onto other pages.
   :has() takes the specificity of its argument, so html:has(.drag-canvas) is (0,1,1)
   and beats the bare `html { scrollbar-gutter: stable }` above without !important.

   • scrollbar-gutter — the site-wide `stable` reserves a 12px strip for a thumb that
     can never appear on a page with nothing to scroll, leaving a dead band down the
     right edge of a full-bleed canvas.
   • overflow — insurance only. The canvas is 100dvh with overflow:hidden, so nothing
     should overflow; this stops a stray margin from introducing a scrollbar anyway.
   • overscroll-behavior — still earns its place even with nothing to scroll: Chrome
     on Android fires pull-to-refresh on a NON-scrollable document. Draggable's
     touch-action:none covers gestures that start inside the mask; this covers the rest. */
html:has(.drag-canvas) {
    scrollbar-gutter: auto;
    overflow: hidden;
    overscroll-behavior: none;
}

/* ─── Work showcase (work-showcase.js + drag-scroller.js) ────────────────── */

/* STATIC GEOMETRY ONLY, and here rather than in Bricks for two different reasons: the
   card's structure repeats across every card, and two of these rules are load-bearing
   in ways that fail silently if a single card is built slightly differently. What
   belongs to one element — the 4/5 aspect ratio, the card width, WHERE the strip sits
   over the image and its flex direction/gap — stays in Bricks' native controls.

   In style.css, not animations.css, because it's layout the Bricks EDITOR must render
   while you build the cards. Only the strip's hover reveal and the thumbnails' resting
   states are front-end-only — see animations.css. */

/* The crop box. `overflow` is the parallax's entire travel budget (the media is
   rendered larger than this box and slides inside it), and `position: relative` is what
   the stage below anchors to. */
.work-showcase-image-wrapper {
    position: relative;
    overflow: hidden;   /* `clip` instead, if a border-radius leaks in Safari */
}

/* The stage: the box drag-scroller parallaxes (it carries .drag-content), holding the
   two image layers work-showcase.js crossfades between.

   ITS SIZE IS NOT OPTIONAL, and this is the subtle one. GSAP puts a transform on this
   element, and a transformed element becomes the containing block for its absolutely-
   positioned descendants — so a stage with no size of its own would collapse both image
   layers to nothing the moment the parallax armed. Pinning it to the crop box here
   makes that impossible to get wrong on any one card. */
.work-showcase-image {
    position: absolute;
    inset: 0;
}

/* The two layers. The second is a JS clone of the first, so both must land in exactly
   the same box — owning that here is what guarantees it, and it keeps the card down to
   ONE Image element in the builder. (Keep it a plain Bricks Image: a caption or a link
   wraps it in a figure/anchor and the two layers stop being siblings.)

   pointer-events:none so the stage never swallows a hover meant for the strip, or a
   grab meant for the row. GSAP owns their opacity — no transition here, ever. */
.work-showcase-image img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    pointer-events: none;
}

/* The strip sits over the stage; its placement is yours to set in Bricks. */
.work-showcase-thumbnails-wrapper {
    z-index: 2;
}

/* Thumbnails. The size is a TOKEN because work-showcase.js reads the same number into
   each thumbnail's `sizes` attribute — so the slot fetches a candidate its own size
   instead of the stage-sized one Bricks would otherwise ask for. Change it in one
   place, and prefer that over sizing a thumbnail in Bricks: an `#brxe-xxxx` width
   would win here but leave `sizes` describing a box that no longer exists.

   ONE DIMENSION PLUS A RATIO, NEVER TWO DIMENSIONS. Setting a width in Bricks writes
   `#brxe-xxxx { width: … }`, and an ID beats this class rule — for `width` only. Declare
   a height here too and that override produces a RECTANGLE — which is exactly how these
   first came out vertical, a 40px width from Bricks against the height this rule used to
   declare — and an `aspect-ratio` set in Bricks can't save it, because a ratio is ignored
   once both dimensions are explicit. With `height: auto` the ratio is always what resolves the second dimension,
   so a per-element width override stays square by construction.

   `height: auto` is also load-bearing on its own: an <img>'s width/height ATTRIBUTES are
   presentational hints for those CSS properties, so without it these would be 1024px
   tall. */
.work-showcase-thumbnails-wrapper img {
    width: var(--ra-showcase-thumb);
    height: auto;
    aspect-ratio: 1 / 1;
    flex-shrink: 0;
    object-fit: cover;
    cursor: pointer;
}

/* ─── Player.style video player (player-style.js) ────────────────────────── */

/* Undoes the two Bricks Video rules that stop being right once the <video> is
   slotted into a <media-theme-*>. Both of Bricks' rules are wrapped in :where(),
   which is ZERO specificity, so a plain class selector wins with no !important:

     :where(.brxe-video) { aspect-ratio:16/9; display:flex; overflow:hidden;
                           position:relative; width:100% }
     :where(.brxe-video) video { height:100%; position:absolute; top:0; width:100% }

   The video rule is a DESCENDANT selector, so it keeps matching after the wrap and
   would leave the video absolutely positioned inside the player's own media slot.
   Bricks' Aspect ratio (written on the root) and Object fit (written as
   `#brxe-xxx video`, also a descendant) both survive the wrap untouched — set them
   in Bricks as usual.

   .ra-player is added by player-style.js instead of styling the media-theme-{slug}
   element directly, so this block doesn't need a rule per player.style theme.

   NOTE: .brxe-video's own `overflow: hidden` clips anything the player draws past
   its box. Minimal and Microvideo have no pop-up menus so nothing is clipped; a
   theme with a settings/quality menu would need that overflow opened up. */
/* `display: grid` IS THE FIX FOR THE "PLAYER SQUISHED TO A THIN LINE" BUG — it is
   not a layout preference, and changing it back to `block` reintroduces the bug.

   Media Chrome's <media-controller> sets `:host { display: inline-block }` with NO
   height, so it shrink-wraps its content instead of filling the theme element. Its
   media slot is `<slot name="media" part="layer media-layer">` carrying
   `display: contents`, so the slot box disappears and the <video> becomes the
   controller's direct in-flow child — meaning the VIDEO is what gives the controller
   its size. Any percentage height on that video is therefore cyclic (it resolves
   against a parent sized by the video itself), collapses toward zero, and takes the
   controller with it. The control-bar layers are `position: absolute; inset: 0`, so
   they collapse too, and you get a thin line.

   Making the host a grid container breaks the cycle from the OUTSIDE. media-controller
   lives in the theme's shadow root, so it can't be selected from this file — but in
   the flattened tree it is still a child box of the host, so as a grid ITEM it is
   blockified and stretched to fill the grid area by default. That gives it a definite
   height sourced from .brxe-video, and the video's `height: 100%` then resolves
   against something real. `display: flex` would work identically; grid just needs no
   extra properties.

   This is also why sizing by the media (the `<media-theme-x style="width:100%">`
   pattern from player.style's own examples) does NOT work here: Bricks' `width: 100%`
   on the video makes its contribution to the controller's shrink-to-fit width cyclic
   as well. Filling the Bricks box is the right model anyway — it's what the un-classed
   widget does, so Bricks' Aspect ratio / width / height controls keep working.

   The height chain is: .brxe-video (definite — :where() gives it aspect-ratio 16/9)
   → .ra-player 100% → media-controller stretched → video 100%. It only holds while
   the root has a definite height, which Bricks always gives it. */
.player-style .ra-player {
    display: grid;
    width: 100%;
    height: 100%;
}

/* `position: static` undoes Bricks pinning the video `absolute`, which would take it
   out of flow and collapse the controller the same way. Set Object fit in Bricks if
   the source ratio doesn't match the box — the default (`fill`) stretches it, exactly
   as it does on an un-classed Bricks video. */
.player-style .ra-player video {
    position: static;
    width: 100%;
    height: 100%;
}

/* -------------------------------------------------------------------------
   logos-outer.js — the injected logo image
   ------------------------------------------------------------------------- */

/* components/logos-outer.js creates this <img> inside each .logo-single, so there's no
   Bricks element to style and its look lives here — same reason .guide-index-scroller
   does above.

   width/height 100% resolve against .logo-single's CONTENT box, i.e. the box MINUS its
   padding. So the 40px inset you set in Bricks is honoured on all four sides and
   `contain` fits the logo inside what's left, centred, never cropped or distorted.

   .logo-single therefore needs a DEFINITE height — aspect-ratio: 1/1, or a fixed px
   height, set in Bricks. Left on `auto` the box takes its height from whichever logo is
   currently inside it, and the whole row jumps every time one swaps.

   GSAP owns this element's opacity (the crossfade). Don't add a CSS transition on it. */
.logo-single > .logo-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}