/* ========================================================================================
   FILE: assets/css/style.css
   PURPOSE: The one stylesheet for the whole Marukab website. It controls every colour,
   font, size, spacing, layout and animation.
   USED BY: every page (index, portfolio, marukab-inn, urban-threads,
   residential-commercial, ongoing-projects, csr, contact). The header and footer are
   built by assets/js/main.js and are styled here too.
   MAP OF SECTIONS (search for the word SECTION to jump): 1 DESIGN SYSTEM, 2 BASE STYLES
   AND TYPOGRAPHY, 3 LAYOUT HELPERS, ACCESSIBILITY AND BUTTONS, 4 HEADER AND NAVIGATION,
   5 HERO, 6 PHOTOS, 7 CONTENT BLOCKS, 8 SECTOR CARDS (HOME), 9 PORTFOLIO CARDS AND
   GALLERIES, 10 FORMS AND TABLES, 11 LIGHTBOX AND SECTION DOTS, 12 FOOTER, 13 REDUCED
   MOTION, 14 SMALL COMPONENTS (header scrim, buttons, slideshow, icons, Urban Threads section,
   contact form extras), 15 INSTAGRAM FEED SECTIONS, 16 PHOTO LAYOUTS FOR THE RESIDENTIAL AND
   CSR PAGES (banner photo positions, 3 and 5 photo galleries, lightbox counter), 17 HOME CSR
   TEASER PHOTO (SHOWN WHOLE), 18 HOME BRAND LOGO
   STRIP (ENDLESS MARQUEE).
   HOW TO EDIT: - Colours, fonts, logo size, header height, paragraph size: change the
   variables in section 1. - Wording is NOT here: it lives in the HTML pages (header and
   footer wording lives in main.js). - To restyle one component, find its section with
   the map above and change only that rule group.
   BRAND RULES: navy #0f2043 is the main colour. Never recolour, stretch or add effects
   (shadow, glow, filter) to the logo. Do not add new colour families.
   ======================================================================================== */
/* ========================================================================================
   SECTION 1: DESIGN SYSTEM (CSS VARIABLES)
   Each variable is a named value used throughout the file. Change a value here and it
   changes everywhere it is used.
   --navy #0f2043: the main brand colour (header, footer, dark sections, headings).
   --navy-d: a darker navy used for the Portfolio dropdown panel. --navy-m: a mid navy
   for photo placeholders, keyboard focus outlines and the slideshow background.
   --navy-l: a light navy for small labels on white. --tint: a pale blue-grey kept in
   reserve (no rule uses it at the moment). --off: the pale background of sections with
   class alt. --ink: normal body text colour. --grey: form label colour. --line: thin
   divider lines.
   --g: Georgia (headings). --v: Verdana (body text, buttons, labels). --ar: Arabic font
   choices for the Arabic word on the home page.
   --hh: header height at the top of the page. --hhs: header height after scrolling.
   --logo-h: height of the header logo AND the footer logo (width follows automatically). To
   resize the logo
   change --logo-h here AND in the 980px media query in the header section. Smaller
   values for tablets and phones are set in that media query.
   --urban-mauve: the Urban Threads brand mauve. Use it only on the Urban Threads page.
   --fs-body, --lh-body, --measure-body: size, line height and maximum line length shared
   by every body paragraph.
   ======================================================================================== */
/* FOOTER VARIABLES (part of the design system, defined in the :root rule just below).
   --ft-gutter: the space at the left and right of every footer row; it equals the page's
   own side margins, so the footer lines up with the content above it (make it larger for
   more side space). --ft-pad: top and bottom padding of the footer's link columns (larger
   gives a taller, airier footer, smaller a tighter one). --ft-gap: the gap between
   location cards. --ft-logo-space: clear space above the footer logo and between the logo
   and the tagline; it is set equal to the logo height (--logo-h) because the logo is the M
   mark, whose clear space is the height of the M. --footer-logo-gap: the space between the
   logo block (logo and tagline) and the Our Locations heading; 2.5rem on desktop and
   tablet and 1.1rem on phones (set in the footer section). Raise it to loosen that gap or
   lower it to tighten it; it is deliberately smaller than the logo's full clear space.
   --ft-card-pad: padding inside each location card, equal on all four sides. --ft-lh: line
   height of all footer text. --ft-tap: minimum height of footer links so they are easy to
   press; 28px on desktop and 44px on phones. */
/* INSTAGRAM VARIABLE: --ig-embed-h is the height of the Instagram feed card on the CSR and
   Urban Threads pages. clamp(520px,75vh,680px) means at least 520px, at most 680px and
   otherwise 75 percent of the screen height. The card reserves this height before the feed
   loads so the page never jumps; change the numbers for a shorter or taller feed. */
/* HEADER, FOOTER AND DROPDOWN COLOUR: --chrome-bg is the ONE solid colour used by the
   header bar, the footer, the full-screen mobile menu panel and the Portfolio dropdown
   panel, so they can never drift apart. It is set to --navy (#0f2043, the footer's own
   background). To change the colour of all four at once, change --chrome-bg in the :root
   rule just below (for example to a hex value); do not give any of them a separate colour.
   The theme-color tag in each page's head should be given the same hex. */
:root{--navy:#0f2043;--navy-d:#0a1630;--navy-m:#243d6d;--navy-l:#5d6f94;--tint:#dfe5f0;--off:#f5f7fa;--ink:#17233c;--grey:#566178;--line:rgba(15,32,67,.15);
--g:Georgia,"Times New Roman",serif;--v:Verdana,Geneva,sans-serif;--ar:"Amiri","Noto Naskh Arabic","Geeza Pro","Traditional Arabic","Times New Roman",serif;--hh:144px;--hhs:128px;--logo-h:96px;--urban-mauve:#b3858f;--fs-body:1rem;--lh-body:1.7;--measure-body:60ch;--ft-gutter:clamp(1.2rem,5vw,4rem);--ft-pad:2rem;--ft-gap:.75rem;--ft-logo-space:var(--logo-h);--ft-card-pad:1.25rem;--ft-lh:1.5;--ft-tap:28px;--footer-logo-gap:2.5rem;--ig-embed-h:clamp(520px,75vh,680px);--chrome-bg:var(--navy)}
/* ========================================================================================
   SECTION 2: BASE STYLES AND TYPOGRAPHY
   Defaults that apply to every page. box-sizing:border-box makes a width include its
   padding and border (easier to predict). margin:0 removes the browser's default
   margins.
   ======================================================================================== */
*,::before,::after{box-sizing:border-box}*{margin:0}
/* Smooth scrolling for in-page links. scroll-padding-top leaves room under the fixed
   header (the scrolled header height plus 1rem) so a jumped-to heading is not hidden
   behind it. */
html{scroll-behavior:smooth;scroll-padding-top:calc(var(--hhs) + 1rem)}
/* Default text: Verdana 0.92rem in the ink colour on white. The animation named in (the
   keyframes rule below) fades the whole page in over half a second when it loads. */
body{font:400 .92rem/1.85 var(--v);color:var(--ink);background:#fff;animation:in .5s}
/* body.out is added by main.js just before leaving for another page and fades the page out
   in a quarter of a second (page transition). body.mo is added while the mobile menu is
   open and stops the page behind it scrolling. */
body.out{opacity:0;transition:opacity .25s}body.mo{overflow:hidden}
@keyframes in{from{opacity:0}}
img{display:block;max-width:100%}a{color:inherit}ul{padding:0}
/* Headings use Georgia Bold in navy. h1 is the page title, h2 a section heading, h3 a card
   or block title. clamp(minimum, preferred, maximum) lets a size grow with the screen
   width between two limits. */
h1,h2,h3{font-family:var(--g);font-weight:700;line-height:1.1;color:var(--navy)}
h1{font-size:clamp(2.3rem,6.4vw,5.6rem)}h2{font-size:clamp(1.9rem,3.8vw,3.3rem)}h3{font-size:1.35rem;line-height:1.25}
/* Adds space between paragraphs that directly follow each other. */
p+p{margin-top:1.1em}
/* ONE paragraph style for every paragraph in the main content of every page: Verdana, size
   --fs-body, line height --lh-body and maximum width --measure-body (about 65 to 70
   characters per line). Eyebrow labels (class eb) are excluded because they are labels,
   not paragraphs. Do not add one-off paragraph sizes; change the three variables instead. */
main p:not(.eb){font:400 var(--fs-body)/var(--lh-body) var(--v);max-width:var(--measure-body)}
/* Eyebrow label: small, widely spaced uppercase text above a heading. The next rule makes
   it lighter on dark backgrounds and over hero photos. */
.eb{font:400 .7rem/1.6 var(--v);letter-spacing:.3em;text-transform:uppercase;color:var(--navy-l);margin-bottom:1.2rem}
.dark .eb,.hero .eb{color:#b7c3dc}
/* ========================================================================================
   SECTION 3: LAYOUT HELPERS, ACCESSIBILITY AND BUTTONS
   .wrap is the centred content column: at most 1240px wide, with side margins that grow
   on wide screens. Almost every section keeps its content inside a .wrap.
   ======================================================================================== */
.wrap{width:min(1240px,100% - clamp(2.4rem,10vw,8rem));margin-inline:auto}
/* Every section gets vertical breathing space that scales with the screen (4rem to 8rem). */
section{padding-block:clamp(4rem,9vw,8rem)}
/* Section themes: .dark gives a navy background, light text and white headings. .alt gives
   a very pale background (--off). Add the class to a section to switch its look. */
.dark{background:var(--navy);color:#dbe3f1}.dark h1,.dark h2,.dark h3{color:#fff}.alt{background:var(--off)}
/* Screen-reader-only text (for example 'opens in a new tab'): shrunk to 1px and clipped so
   sighted users do not see it while screen readers still read it. display:none would hide
   it from screen readers too. */
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
/* Skip link: parked off-screen above the page and moved into view when a keyboard user
   presses Tab, so they can jump past the header to the main content. */
.skip{position:absolute;left:1rem;top:-5rem;z-index:99;background:#fff;color:var(--navy);padding:.8rem 1.2rem}.skip:focus{top:1rem}
/* Keyboard focus ring: a visible outline on whatever has keyboard focus. The next rule
   makes it white on dark areas so it stays visible. Do not remove focus outlines; keyboard
   users depend on them. */
:focus-visible{outline:3px solid var(--navy-m);outline-offset:3px}
.dark :focus-visible,.hero :focus-visible,#hdr :focus-visible,#ft :focus-visible,.lb :focus-visible,#mm :focus-visible{outline-color:#fff}
/* Buttons (class btn): small tracked uppercase text on navy; on hover they invert to white
   with navy text. On dark sections and the hero they start white and turn transparent on
   hover (third rule). Variant .btn.o (outline) is further down. */
.btn{display:inline-block;font:400 .7rem/1 var(--v);letter-spacing:.24em;text-transform:uppercase;text-decoration:none;padding:1.2rem 2.1rem;background:var(--navy);color:#fff;border:1px solid var(--navy);cursor:pointer;transition:background .3s,color .3s}
.btn:hover{background:#fff;color:var(--navy)}
.dark .btn,.hero .btn{background:#fff;color:var(--navy);border-color:#fff}.dark .btn:hover,.hero .btn:hover{background:transparent;color:#fff}
/* ========================================================================================
   SECTION 4: HEADER AND NAVIGATION
   The header, Portfolio dropdown and mobile menu are created by assets/js/main.js; these
   rules style them. #hdr is the bar fixed to the top of every page. Its colour is always
   the solid --chrome-bg (the same variable as the footer, the mobile menu panel and the
   dropdown), at the top of the page, after scrolling and while the menu is open: there
   is no transparent state, no dark scrim and no blur. Its height is --hh at the top and
   --hhs once scrolled (height changes over 0.4 seconds). z-index 60 keeps it above page
   content. The header also slides up out of view (0.25 seconds) while the footer logo is
   near the top of the screen; see the tuck rule after the scrolled-height rule.
   ======================================================================================== */
#hdr{position:fixed;top:0;left:0;right:0;z-index:60;height:var(--hh);background:var(--chrome-bg);color:#fff;transition:height .4s,transform .25s ease}
/* Scrolled state: main.js adds class s to the header once the visitor has scrolled more
   than 40px (body.mo applies the same height while the mobile menu is open). Only the
   height changes, to the slimmer --hhs; the colour is the same solid --chrome-bg in every
   state and the logo keeps the same size. */
#hdr.s,body.mo #hdr{height:var(--hhs)}
/* Header tuck: main.js adds the class site-header--tucked to the header while the footer
   logo block is near the top of the screen (see the HEADER TUCK section in main.js), so
   the header logo is never seen stacked above the footer logo. The header slides straight
   up by its own height (translateY(-100%)); the 0.25s ease is the transform part of the
   #hdr transition above (safe to change, about 0.2 to 0.4s), and reduced motion removes it
   so the header just appears or disappears. Everything attached to the header (the bar,
   its colour and the Portfolio dropdown inside it) moves with it, so nothing is left
   behind at the top of the screen. The header stays focusable (it is moved, never hidden
   with visibility or display). */
.site-header--tucked{transform:translateY(-100%)}
/* Inner row of the header (it also has class wrap): logo on the left, navigation on the
   right, vertically centred. */
#hdr .in{height:100%;display:flex;align-items:center;justify-content:space-between;gap:2rem}
/* Logo link and image. Height is --logo-h and width is automatic, so the proportions never
   change. BRAND RULE: never recolour, stretch, distort or add effects (shadow, glow,
   filter) to the logo. */
#hdr .logo{display:flex;align-items:center}
#hdr .logo img{height:var(--logo-h);width:auto}
/* Desktop navigation: a row of small tracked uppercase links, each as tall as the header
   so the Portfolio dropdown opens directly beneath the bar. Hidden below 980px (see that
   media query). */
#hdr nav{display:flex;gap:2.6rem;height:100%}
#hdr nav>a,#hdr .has>a{position:relative;display:flex;align-items:center;height:100%;font:400 .7rem var(--v);letter-spacing:.24em;text-transform:uppercase;text-decoration:none}
/* Underline animation: a 1px white line under each link, squashed to zero width and grown
   from the left on hover. It stays visible on the link for the page you are on
   (aria-current). bottom:calc(50% - 18px) places it just under the text because the link
   is as tall as the header. */
#hdr nav>a::after,#hdr .has>a::after{content:"";position:absolute;left:0;right:0;bottom:calc(50% - 18px);height:1px;background:#fff;transform:scaleX(0);transform-origin:left;transition:transform .35s}
#hdr nav>a:hover::after,#hdr .has:hover>a::after,#hdr nav>a[aria-current]::after,#hdr .has>a[aria-current]::after{transform:scaleX(1)}
/* Portfolio item: a flex row holding the Portfolio link, the chevron button and
   (positioned underneath) the dropdown list. position:relative makes the dropdown's
   top:100% measure from the header's real height, so there is no hard-coded pixel gap and
   no gap that could close the menu as the pointer moves down. */
#hdr .has{position:relative;display:flex;align-items:center;height:100%}
/* Chevron button after the Portfolio label: a small white arrow (about 11px) in a button
   as tall as the header. It opens and closes the dropdown (aria-expanded is set by
   main.js) and the arrow turns upside down while the menu is open (class open on the
   Portfolio item). */
.chev{display:grid;place-items:center;width:36px;height:100%;padding:0;background:none;border:0;color:#fff;cursor:pointer}
.chev svg{width:11px;height:11px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;transition:transform .16s ease}
.has.open .chev svg{transform:rotate(180deg)}
/* Portfolio dropdown (desktop): a compact 280px panel directly under the Portfolio item,
   left edge aligned to it (class sub-r, added by main.js only if it would run past the
   right edge of the window, aligns it to the right edge instead). Solid --chrome-bg
   background (exactly the header and footer colour: no gradient, no transparency, no
   blur), a 1px border in the footer-card line colour and a soft low shadow so it separates
   from the page. Hidden until opened (invisible, 8px lower); opening fades it in and
   slides it up over 0.16s (reduced motion removes the animation). While hidden it cannot
   be tabbed into. HOW TO ADD, REMOVE OR REORDER AN ITEM: edit the P list in
   assets/js/main.js; the same list builds this dropdown, the mobile accordion and the
   footer quick links, and no CSS change is needed. If you add a longer label, raise the
   280px width. */
.sub{position:absolute;left:0;top:100%;z-index:5;width:280px;max-width:calc(100vw - 2rem);margin:0;padding:0;list-style:none;background:var(--chrome-bg);border:1px solid rgba(255,255,255,.18);box-shadow:0 14px 30px rgba(10,22,48,.28);opacity:0;visibility:hidden;transform:translateY(8px);transition:opacity .16s ease,transform .16s ease,visibility 0s .16s}
.sub.sub-r{left:auto;right:0}
.has.open .sub{opacity:1;visibility:visible;transform:none;transition-delay:0s}
/* Dropdown rows: white Verdana 0.9rem names only, each row at least 44px high with 0.75rem
   and 1.25rem padding and a thin divider (the footer-card line colour) between rows.
   Hover, keyboard focus and the current page show a slightly lighter navy (--navy-m, from
   the palette) plus a 2px white bar on the left edge; the focus ring is drawn inside the
   row so it is never cut off. The row for the page you are on has aria-current set by
   main.js. */
.sub li+li{border-top:1px solid rgba(255,255,255,.18)}
.sub a{position:relative;display:flex;align-items:center;min-height:44px;padding:.75rem 1.25rem;font:400 .9rem/1.3 var(--v);color:#fff;text-decoration:none}
.sub a::before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:#fff;opacity:0}
.sub a:hover,.sub a:focus-visible,.sub a[aria-current]{background:var(--navy-m)}
.sub a:hover::before,.sub a:focus-visible::before,.sub a[aria-current]::before{opacity:1}
.sub a:focus-visible{outline-offset:-3px}
/* Menu (hamburger) button: hidden on desktop and shown below 980px. Its two bars are i
   elements; while body.mo is set they rotate into an X. z-index 71 keeps it above the
   full-screen menu. */
#bg{display:none;position:relative;z-index:71;width:48px;height:48px;background:none;border:0;cursor:pointer}
#bg i{position:absolute;left:12px;right:12px;height:2px;background:#fff;transition:.35s}#bg i:first-child{top:18px}#bg i:last-child{top:28px}
body.mo #bg i:first-child{top:23px;transform:rotate(45deg)}body.mo #bg i:last-child{top:23px;transform:rotate(-45deg)}
/* Full-screen mobile menu. It covers the screen but is hidden by a clip-path cut off at
   the bottom plus visibility hidden. While body.mo is set the clip opens downward
   (clip-path:inset(0)) over 0.6 seconds. The links fade and slide up one after another:
   each link has an index number (--i, set by main.js) that is multiplied into a small
   delay. Top padding keeps the links below the header. The panel colour is --chrome-bg (the
   same as the header). The Portfolio row (link plus chevron button) and its collapsible list
   of five items are styled by the accordion rules right after the link rules. */
#mm{position:fixed;inset:0;z-index:55;display:flex;flex-direction:column;gap:.5rem;padding:calc(var(--hhs) + 1.5rem) clamp(1.4rem,6vw,3rem) 2rem;background:var(--chrome-bg);overflow:auto;visibility:hidden;clip-path:inset(0 0 100% 0);transition:clip-path .6s cubic-bezier(.7,0,.2,1),visibility 0s .6s}
body.mo #mm{visibility:visible;clip-path:inset(0);transition-delay:0s}
#mm a{font:700 clamp(1.6rem,7vw,2.3rem)/1.3 var(--g);color:#fff;text-decoration:none;opacity:0;transform:translateY(18px);transition:.5s}
body.mo #mm a{opacity:1;transform:none;transition-delay:calc(.25s + var(--i)*.05s)}
/* Mobile menu tap targets: every top-level row of the full-screen menu (Shop, CSR, Contact
   Us; the Portfolio row is already 48px tall because of its chevron button) is a flex box
   at least 44px high with its text centred, so each row is a comfortable tap target even
   on the smallest phones, where the large text alone made the rows only about 33px high.
   On wider screens the rows were already taller, so nothing changes there. To make the
   rows taller or shorter change the 44px. */
#mm>a{display:flex;align-items:center;min-height:44px}
/* Portfolio accordion in the mobile menu: the row holds the Portfolio link (left) and a
   chevron button (right, 48px square, so an easy tap target) that unfolds the list in
   place. The list is collapsed by default and animates its height smoothly (the
   grid-template-rows trick from 0fr to 1fr over 0.3s; reduced motion removes the
   animation); while collapsed it is invisible so its links cannot be tabbed into. main.js
   folds it back up whenever the menu closes. The items are indented, 44px or more high,
   separated by the footer-card line colour, and the current page is tinted --navy-m with a
   2px white bar, like the desktop dropdown. */
#mm .mrow{display:flex;align-items:center;justify-content:space-between}
#mm .mrow a{flex:1}
.mchev{display:grid;place-items:center;flex:none;width:48px;height:48px;padding:0;background:none;border:0;color:#fff;cursor:pointer}
.mchev svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;transition:transform .2s ease}
.mchev[aria-expanded="true"] svg{transform:rotate(180deg)}
.msub{display:grid;grid-template-rows:0fr;visibility:hidden;transition:grid-template-rows .3s ease,visibility 0s .3s}
.msub.open{grid-template-rows:1fr;visibility:visible;transition:grid-template-rows .3s ease}
.msub ul{min-height:0;margin:0;padding:0;overflow:hidden;list-style:none}
#mm .msub a{position:relative;display:flex;align-items:center;min-height:44px;padding:.75rem 1rem .75rem 1.25rem;font:400 .95rem/1.3 var(--v);border-top:1px solid rgba(255,255,255,.18)}
#mm .msub a::before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:#fff;opacity:0}
#mm .msub a:hover,#mm .msub a:focus-visible,#mm .msub a[aria-current]{background:var(--navy-m)}
#mm .msub a:hover::before,#mm .msub a:focus-visible::before,#mm .msub a[aria-current]::before{opacity:1}
/* Applies to screens 980px wide or narrower (tablets and phones): the header gets smaller
   values (height 112px, 104px once scrolled, logo 80px), the desktop links are hidden and
   the hamburger button is shown. */
@media(max-width:980px){:root{--hh:112px;--hhs:104px;--logo-h:80px}#hdr nav{display:none}#bg{display:block}}
/* ========================================================================================
   SECTION 5: HERO (OPENING PANEL OF EVERY PAGE)
   The large navy opening panel. It starts BELOW the solid header (margin-top is the
   header height, --hh), so the header never covers the top of the hero photo or the
   heading. On the home page it fills the rest of the screen (100svh minus the header
   height; svh is the height of the visible screen even when a phone address bar is
   showing). Inner pages add class sm (72svh minus the header height). Content sits at
   the bottom (align-items:flex-end) with a little top padding. overflow:hidden crops the
   moving line drawing and photos. .hero .wrap has z-index 2 so text sits above those
   layers.
   ======================================================================================== */
.hero{position:relative;min-height:calc(100svh - var(--hh));margin-top:var(--hh);display:flex;align-items:flex-end;padding:3rem 0 5rem;background:var(--navy);color:#fff;overflow:hidden}
.hero.sm{min-height:calc(72svh - var(--hh))}.hero .wrap{position:relative;z-index:2}
.hero h1{color:#fff;max-width:16ch}.hero p:not(.eb){margin-top:1.6rem;color:#dbe3f1}.hero .btn{margin-top:2.4rem}
/* Decorative thin-line shapes (sails and beams) that main.js adds to every hero. It is
   slightly taller than the hero (inset:-6% 0) so it can slide with the page as you scroll
   (parallax) without showing gaps. pointer-events:none lets clicks pass through it.
   vector-effect keeps the lines 1px thin however the drawing is scaled. */
.geo{position:absolute;inset:-6% 0;z-index:1;pointer-events:none;will-change:transform}.geo svg{width:100%;height:100%}.geo path{vector-effect:non-scaling-stroke}
/* Home page cycling headline (class kin). Each keyword is a span that slides up and fades
   in when the page loads (animation 'up', delayed 0.15 seconds per keyword using its index
   --i). About 2.6 seconds later main.js adds class cy: all keywords dim to 45% and class
   on moves from keyword to keyword every 1.9 seconds, so one is always highlighted. */
.hero h1.kin{max-width:none;text-transform:uppercase;font-size:clamp(2.2rem,7.2vw,6.4rem);line-height:1.02}
.kin span{display:block;transition:opacity .7s;animation:up 1s cubic-bezier(.2,.7,.2,1) backwards;animation-delay:calc(var(--i)*.15s + .3s)}
.kin.cy span{opacity:.45}.kin.cy span.on{opacity:1}
/* Narrow phones (400px wide or less): at the normal minimum size (2.2rem) the longest
   keyword, CONSTRUCTION., is wider than a 320px screen and its last letters were cut off
   by the hero's overflow:hidden. Here the headline scales with the screen width (8.4vw),
   never smaller than 1.7rem and never larger than 2.2rem, so the word fits at 320px. From
   401px upwards the size is the same as before. */
@media(max-width:400px){.hero h1.kin{font-size:clamp(1.7rem,8.4vw,2.2rem)}}
/* Entrance animation: starts 60px lower and invisible, ends in its normal place. */
@keyframes up{from{opacity:0;transform:translateY(60px)}}
/* ========================================================================================
   SECTION 6: PHOTOS
   .ph is a photo box. It crops the image to fill the box (object-fit:cover), shows a mid
   navy while loading, and slowly zooms the image on hover (the scale rule below). Hero
   photos fill the whole hero (.hero .ph).
   ======================================================================================== */
.ph{position:relative;overflow:hidden;background:var(--navy-m)}
.ph img{width:100%;height:100%;object-fit:cover;transition:transform 1.2s cubic-bezier(.2,.7,.2,1)}
.hero .ph{position:absolute;inset:0}
a:hover>.ph img,button.ph:hover img,.split .ph:hover img{transform:scale(1.06)}
/* Navy gradient overlay (35% navy at the top to 90% at the bottom) laid over photos that
   carry text: hero photos, portfolio cards and sector cards. It keeps white text readable.
   Keep it consistent across the site. */
.hero .ph::after,.card .ph::after,.acc .ph::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(10,22,48,.35),rgba(15,32,67,.9))}
/* Swap-me placeholder: if a photo cannot load, main.js adds class sw and the file name
   (kept in attribute data-f) is shown on a diagonal-lined navy panel, so you can see which
   file is missing. */
.ph.sw::before{content:"Swap me: " attr(data-f);position:absolute;inset:0;display:grid;place-items:center;padding:1rem;text-align:center;color:#b7c3dc;font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;background:repeating-linear-gradient(135deg,transparent 0 22px,rgba(255,255,255,.06) 22px 23px)}
/* ========================================================================================
   SECTION 7: CONTENT BLOCKS
   .split makes two equal columns (text beside an image, or two text blocks) with a gap
   that scales with the screen. .split.r swaps the order so the first block appears on
   the right. .split .ph forces a 4 by 5 portrait shape for photos inside these blocks.
   ======================================================================================== */
.split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(2rem,6vw,6rem);align-items:center}.split.r>:first-child{order:2}
.split .ph{aspect-ratio:4/5}
/* Applies to screens 860px wide or narrower: .split becomes one column and the left-right
   swap is cancelled, so blocks follow their order in the HTML. */
@media(max-width:860px){.split{grid-template-columns:1fr}.split.r>:first-child{order:0}}
/* The Arabic word in the 'Our name' section: very large, centred, using the Arabic font
   choices in --ar. */
.ar{font:400 clamp(6rem,16vw,13rem)/1.5 var(--ar);text-align:center;color:var(--navy)}
/* Call-to-action band: heading on the left and button on the right; wraps on narrow
   screens. */
.band{display:flex;justify-content:space-between;align-items:center;gap:2rem;flex-wrap:wrap}
/* Amenity columns (Marukab Inn): as many columns of at least 260px as fit. Each group has
   a heading with a rule under it and a list with thin dividers. The item layout (icon plus
   text) is set by .cols li near the end of this file. */
.cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:3rem}
.cols h3{padding-bottom:1rem;margin-bottom:.6rem;border-bottom:2px solid var(--navy)}.cols li{list-style:none;padding:.7rem 0;border-bottom:1px solid var(--line)}
/* Information card: a navy rule across the top and tidy spacing, used for contact details. */
.info{border-top:2px solid var(--navy);padding-top:1.4rem}.info h3{margin-bottom:.8rem}.info p+p{margin-top:.5em}
/* A row of outlined chips (for example the types of commercial space). */
.tags{display:flex;flex-wrap:wrap;gap:.7rem;list-style:none;margin-top:1.6rem}.tags li{border:1px solid var(--navy);padding:.55rem 1.1rem;font-size:.78rem}
/* SECTION 19: THE RESIDENTIAL AND COMMERCIAL SPACES BAR ON THE HOME PAGE (class rc-line on
   the section, together with the shared navy-band class dark, and rc-text on the b tag;
   the markup and the wording notes are in index.html). It is a full-width navy bar with a
   single centred line of white Georgia Bold in one column inside the standard container,
   with no border, shadow, gradient, pattern or divider. THE VARIABLES, all on the rc-line
   rule below (written with two leading hyphens): rc-bg is the colour of the bar and is the
   variable chrome-bg, the navy that the header and the footer use, so the three always
   match; rc-fg is the text colour, white (#ffffff), which has a contrast of about 16 to 1
   on that navy (4.5 to 1 is needed); rc-fs is the font-size, clamp(1.75rem, 4vw, 3.5rem),
   where the three numbers are the smallest size, the share of the window width and the
   largest size (clamp(2.25rem, 5vw, 4.5rem) gives a bigger line); rc-pad is the padding
   above and below the text, clamp(3rem, 7vw, 6rem), the same on both sides so the text
   sits in the middle of the bar, and it sets the height of the bar together with the text
   (about 240px at 1280px wide). The bar is a section, so it runs from edge to edge of the
   window and its straight edges meet the sections above and below with no gap and no
   overlap. HOW THE TEXT IS KEPT CENTRED: the container (class wrap) has equal automatic
   margins on both sides, the b tag is a block that fills it, and text-align center centres
   the words inside it; nothing is offset, transformed or placed at a fixed position, so
   the text's centre is the page's centre at every width. The line-height is 1.2; text-wrap
   balance gives two even lines when the text does not fit on one, and a word is never
   broken or hyphenated; the ampersand stays with the next word through the non-breaking
   space in the HTML. THE DOTS ON THE RIGHT EDGE need no rule here: the dots (section 11)
   have a white outline and mix-blend-mode difference, which inverts whatever is under
   them, so over this navy bar they appear light cream (a contrast of about 12 to 1 on the
   navy) and over the white and off-white sections they are dark; the text, centred in the
   container, is far from the dots at the window's right edge. */
.rc-line{--rc-pad:clamp(3rem,7vw,6rem);--rc-fs:clamp(1.75rem,4vw,3.5rem);--rc-bg:var(--chrome-bg);--rc-fg:#fff;padding-block:var(--rc-pad);background:var(--rc-bg);text-align:center}
.rc-text{display:block;font:700 var(--rc-fs)/1.2 var(--g);color:var(--rc-fg);text-align:center;text-wrap:balance;hyphens:none;overflow-wrap:normal;word-break:normal}
/* SECTION 20: the fitted label on the Residential and Commercial Spaces page (class
   fit-text, inside the cell fit-cell). It is Georgia Bold in white, like the big text
   elsewhere, centred (text-align center), and is never stretched or spaced out; only its
   font-size and line-height change. nw keeps the hyphenated word on one line, so it never
   breaks at its hyphen. The text balances over two to four lines, never hyphenates and
   never breaks inside a word. SIZES: the variables fit-min (1.75) and fit-max (5), both in
   rem and written with two leading hyphens, are the smallest and largest size the script
   may choose when it fits the label to the right-hand content; the script also never goes
   above the size of the page's main heading (the h1). THE RATIO: the variable fit-ratio
   (0.738) on the same rule is how much of that fitted size the label is actually shown at, so
   the label is about 26 percent smaller than the full fit; to make it bigger or smaller change
   only this number (1 is the full fitted size, 0.6 is smaller). The script and the CSS
   fallback below both multiply by it, so they give the same size, and neither goes below the
   smallest size fit-min. It also multiplies
   the CSS fallback sizes, so the page looks the same without JavaScript. VERTICAL
   CENTRING: fit-cell has align-self center, so where the two columns sit side by side the
   label's cell is centred against the right-hand content (its middle level with the middle
   of that content); nothing is padded or moved by the script. In the one-column layout the
   label is simply centred above the content. THE FITTING: where the two columns sit side
   by side, the script FIT TEXT in main.js measures the right-hand content and writes
   fit-fs (font-size) and fit-lh (line-height). Those variables sit on top of the fallback
   values fit-f0 and fit-l0 below, which are what shows without JavaScript. FALLBACKS
   (multiplied by fit-ratio and never below fit-min): one column (up to 860px wide, the same
   width as the split
   rule): the largest size that fits the column on at most three lines, but never above the
   h1 size (the width of the content divided by 7.2 is a safe limit for the long hyphenated
   word in Georgia Bold); two columns (from 861px): 6vw between 1.75rem and 5rem, again
   limited to half the content width (less the gap) divided by 7.2, with a line-height of
   1.2. The 860px here must match the 860px in the script and in the split rule. */
.fit-cell{align-self:center;min-width:0}
.fit-text{--fit-min:1.75;--fit-max:5;--fit-ratio:.738;--fit-f0:max(calc(var(--fit-min)*1rem),calc(var(--fit-ratio)*min(clamp(2.3rem,6.4vw,5.6rem),calc((100vw - clamp(2.4rem,10vw,8rem))/7.2))));--fit-l0:1.15;display:block;font:700 var(--fit-fs,var(--fit-f0))/var(--fit-lh,var(--fit-l0)) var(--g);color:#fff;text-align:center;text-wrap:balance;hyphens:none;overflow-wrap:normal;word-break:normal}
.nw{white-space:nowrap}
@media(min-width:861px){.fit-text{--fit-f0:max(calc(var(--fit-min)*1rem),calc(var(--fit-ratio)*min(clamp(1.75rem,6vw,5rem),calc(((100vw - clamp(2.4rem,10vw,8rem)) - clamp(2rem,6vw,6rem))/2/7.2))));--fit-l0:1.2}}
/* Scroll reveal: elements with class rv start invisible and 24px lower. main.js adds class
   in when they scroll into view and they fade up over 0.9 seconds. */
.rv{opacity:0;transform:translateY(24px);transition:opacity .9s,transform .9s}.rv.in{opacity:1;transform:none}
/* ========================================================================================
   SECTION 8: SECTOR CARDS (HOME PAGE, EXPLORE OUR SECTORS)
   An expanding row of four photo cards (class acc). Each card is a link (.acc a) holding
   a photo (.ph) and a title (.t). The open card (class on, set by main.js) grows to 4.5
   times the width of a closed card (flex:4.5 against flex:1) with a smooth 0.8 second
   transition. Cards sit in the order they appear in the HTML, and the first card in the
   HTML is open by default. Text sits above the photo and its navy overlay.
   ======================================================================================== */
.acc{display:flex;gap:6px;height:min(72vh,640px)}
.acc a{position:relative;flex:1;display:flex;align-items:flex-end;overflow:hidden;color:#fff;text-decoration:none;transition:flex .8s cubic-bezier(.2,.7,.2,1)}.acc a.on{flex:4.5}
.acc .ph{position:absolute;inset:0}.acc .t{position:relative;z-index:2;padding:clamp(1.4rem,2.4vw,2.2rem)}
/* Card titles: large Georgia. In closed cards the title runs vertically
   (writing-mode:vertical-rl, flipped 180 degrees so it reads from bottom to top); in the
   open card it is horizontal. */
.acc h3{color:#fff;font-size:clamp(1.5rem,2.4vw,2.2rem);line-height:1.15}.acc a:not(.on) h3{writing-mode:vertical-rl;transform:rotate(180deg)}
/* Applies to screens 800px wide or narrower: the cards stack in a column. Closed cards are
   88px strips, the open card is 340px tall, and titles are horizontal. */
@media(max-width:800px){.acc{flex-direction:column;height:auto}.acc a{flex:none;min-height:88px;transition:min-height .6s}.acc a.on{min-height:340px}.acc a:not(.on) h3{writing-mode:horizontal-tb;transform:none}}
/* ========================================================================================
   SECTION 9: PORTFOLIO CARDS AND GALLERIES
   .cards is a six-column grid on the Portfolio page. Each .card spans 2 columns (three
   per row) except the first two cards (:nth-child(-n+2)), which span 3 columns and are
   taller (560px) as the featured pair. Card text sits at the bottom over the navy
   gradient overlay.
   ======================================================================================== */
.cards{display:grid;grid-template-columns:repeat(6,1fr);gap:1rem}
.card{position:relative;grid-column:span 2;min-height:460px;display:flex;align-items:flex-end;overflow:hidden;color:#fff;text-decoration:none}.card:nth-child(-n+2){grid-column:span 3;min-height:560px}
.card .ph{position:absolute;inset:0}.card .ct{position:relative;z-index:2;padding:2rem}.card h3{color:#fff;font-size:1.7rem;margin-bottom:.8rem}
.more{display:inline-block;margin-top:1.2rem;padding-bottom:.3rem;border-bottom:1px solid #fff;font-size:.7rem;letter-spacing:.24em;text-transform:uppercase}
/* Applies to screens 900px wide or narrower: one card per row, 420px high. */
@media(max-width:900px){.cards{grid-template-columns:1fr}.card,.card:nth-child(-n+2){grid-column:auto;min-height:420px}}
/* Photo galleries: a grid of thumbnails at least 260px wide in a 4 by 3 shape. Each
   thumbnail is a button; clicking one opens the lightbox (main.js). Hover zooms the photo. */
.gal{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:1rem}
.gal button{display:block;width:100%;aspect-ratio:4/3;padding:0;border:0;cursor:zoom-in}
/* Inn and Urban Threads galleries (classes inn and ed): a plain grid of uniform tiles.
   Every tile is a 3 by 4 portrait box; the box crops what you see (object-fit:cover),
   never the photo file, and the lightbox shows each photo whole. 3 equal columns from
   600px wide upwards, 2 columns below 600px. Nine Inn photos: 3 rows of 3 on tablet and
   desktop; on phones the first photo spans both columns (the rule after the media query)
   and the other eight fill 4 rows of 2. Six Urban Threads photos: 2 rows of 3 on tablet
   and desktop, 3 rows of 2 on phones. So the last row is always full: no empty cells at
   any width. minmax(0,1fr) lets columns shrink instead of being pushed wider by a photo. */
.gal.inn,.gal.ed{grid-template-columns:repeat(3,minmax(0,1fr))}.gal.inn button,.gal.ed button{aspect-ratio:3/4}
@media(max-width:599px){.gal.inn,.gal.ed{grid-template-columns:repeat(2,minmax(0,1fr))}.gal.inn button:first-child{grid-column:1/-1}}
/* Photo focal points inside a cropped box (object-position: across down). pos-dresses is
   used for the Urban Threads header photo in the hero: 50% across and 36% down keeps the
   patterned sleeves and fabric in view when the portrait photo is cropped to a wide band.
   pos-rack is used for the landscape collection photo in its 3 by 4 tile: 58% across keeps
   the clothes rail centred. pos-shop is used for the boutique interior on the Urban Threads
   card of the Portfolio page and on the Fashion Retail card of the Home page (the same photo;
   the closed Home card shows only a thin strip of it): 85% across keeps the rack of patterned
   shirts on the
   right in view when the card is cropped to a portrait shape (the 50% down keeps the rails
   in view when the card is cropped wide). Change the percentages to reframe; 0% is the
   left or top edge and 100% the right or bottom edge. */
.pos-dresses{object-position:50% 36%}.pos-rack{object-position:58% 50%}.pos-shop{object-position:85% 50%}
/* Marukab Plaza card photo (the Hospitality card on the Home page and the Marukab Plaza card on
   the Portfolio page): the photo is a tall portrait of the building, so each card crops a
   band of it. 50% across centres the building and 80% down keeps the lit ground floor with
   the Plaza sign in view. Change the percentages to reframe; 0% is the left or top edge
   and 100% the right or bottom edge. */
.pos-plaza{object-position:50% 80%}
/* Marukab Inn card photo on the Portfolio page (the second Inn gallery photo, a portrait
   of a bed in a teal room): the card crops a band of it, and the band changes with the
   card width (a wide single card on tablets, a squarer card on desktop). 50% across
   centres the photo and 85% down keeps the bed fully in view at every width, trading away
   the lamp and ceiling fan at the top when the band is thin. Change the percentages to
   reframe; 0% is the left or top edge and 100% the right or bottom edge. */
.pos-innroom{object-position:50% 85%}
/* Photos on the Home and Portfolio cards that now come from the site's own files. Each
   class is an object-position (across, down) that keeps the subject in view when the card
   crops the photo; the Home cards are a wide 8 by 7 box when open, a thin strip when
   closed and a short band on phones, so the values suit all three shapes. pos-homere is
   the Home Real Estate card (residential-02.jpg, a tall white block photographed from
   below): 40% down keeps the building in the middle. pos-homecon is the Home Construction card
   (marukab-beach-spotlight.jpg, a square photo): 84% across keeps the worker in the printed
   shirt in the middle of the thin closed strip, and 37% down keeps his hard hat and shirt in
   the narrow band on phones. pos-homehiya is the Marukab Hiya spotlight photo on the Home page
   (marukab-hiya-spotlight.jpg, a tall photo in a 4 by 5 box): 60% down keeps all the workers
   in view while only a little is cropped. pos-pfong is the Ongoing Projects card on the
   Portfolio page (marukab-beach-spotlight.jpg again): 75% across keeps the worker inside the
   narrow portrait card, and 45% down keeps his hard hat and upper body in the top two thirds
   of the wide short card on tablets, where the title does not cover them. pos-pfres is the
   Portfolio Residential
   and Commercial Spaces card (residential-03.jpg): 28% down keeps the upper part of the
   building, with its balconies, in the top two thirds, where the title does not cover it.
   Change the percentages to reframe; 0% is the left or top edge and 100% the right or
   bottom edge. */
.pos-homere{object-position:50% 40%}.pos-homecon{object-position:84% 37%}.pos-homehiya{object-position:50% 60%}.pos-pfong{object-position:75% 45%}.pos-pfres{object-position:50% 28%}
/* ========================================================================================
   SECTION 10: FORMS AND TABLES
   Form layout (contact page): fields stacked with spacing. Labels are small uppercase
   text. The select box and message box have a grey-blue border that is dark enough to
   see clearly.
   ======================================================================================== */
form{display:grid;gap:1.2rem}label{display:grid;gap:.5rem;font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;color:var(--grey)}
select,textarea{font:400 .92rem var(--v);padding:.9rem 1rem;border:1px solid #76829b;border-radius:0;background:#fff;color:var(--ink)}textarea{min-height:9rem}
/* Opening hours table: rows with thin dividers and right-aligned times. */
table{border-collapse:collapse;width:100%}td{padding:.6rem 0;border-bottom:1px solid var(--line)}td:last-child{text-align:right}
/* ========================================================================================
   SECTION 11: LIGHTBOX AND SECTION DOTS
   .lb is the full-screen photo viewer that main.js creates on pages with gallery
   thumbnails. It sits above everything (z-index 100) on a dark navy tint. The photo is
   limited to 92% of the screen width and 78% of its height. The rule .lb[hidden] keeps
   it invisible until a thumbnail is clicked. Its buttons are close, previous and next, and a
   small counter at the top shows which photo is open (for example 3 / 9).
   ======================================================================================== */
.lb{position:fixed;inset:0;z-index:100;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:4rem 1rem 3rem;background:rgba(10,22,48,.96)}.lb[hidden]{display:none}
.lb img{max-width:min(1100px,92vw);max-height:78vh;object-fit:contain}.lb p{margin-top:1rem;color:#dbe3f1;font-size:.8rem;text-align:center}
.lb button{position:absolute;width:48px;height:48px;background:none;border:1px solid rgba(255,255,255,.45);color:#fff;font-size:1.6rem;cursor:pointer}.lb .x{top:1rem;right:1rem}.lb .pv{left:1rem;top:50%}.lb .nx{right:1rem;top:50%}
/* Section dots: a column of small diamonds fixed to the right edge, built by main.js with
   one per page section; the diamond of the section on screen is filled.
   mix-blend-mode:difference makes the white dots show on both light and dark sections. */
.dots{position:fixed;right:1.4rem;top:50%;z-index:40;display:grid;gap:1rem;transform:translateY(-50%);mix-blend-mode:difference}
.dots a{display:block;width:10px;height:10px;border:1px solid #fff;transform:rotate(45deg)}.dots a.on{background:#fff}
/* Applies to screens 1100px wide or narrower: the dots are hidden so they do not crowd the
   content. */
@media(max-width:1100px){.dots{display:none}}
/* ========================================================================================
   SECTION 12: FOOTER
   The footer is created by assets/js/main.js and is identical on every page. Background colour
   --chrome-bg (shared with the header, the mobile menu and the dropdown), light text, one
   shared text size (0.82rem, rule '#ft p') and one shared
   line height (--ft-lh). Its spacing is controlled by the --ft-* variables and
   --footer-logo-gap listed in the comment above the :root rule. The footer logo is the
   same white icon logo as the header and takes its height from the same variable
   (--logo-h), so the two always match.
   ======================================================================================== */
/* Footer base: background --chrome-bg (shared with the header, the mobile menu and the
   dropdown), light text, 0.82rem, line height from --ft-lh. Links have
   no underline until hovered. */
#ft{background:var(--chrome-bg);color:#cfd8ea;font-size:.82rem;line-height:var(--ft-lh)}#ft a{text-decoration:none}#ft a:hover{text-decoration:underline}
/* Footer container: the same centred column as the page content (at most 1240px), but with
   explicit side padding (--ft-gutter) so every footer row, from the Our Locations heading
   to the copyright bar, has comfortable space at the left and right. The gutter equals the
   page's own side margins, so the footer's edges line up with the content above.
   width:100% plus the max-width (1240px plus the two gutters) keeps the text column 1240px
   wide on large screens. */
#ft>.wrap{width:100%;max-width:calc(1240px + 2*var(--ft-gutter));padding-inline:var(--ft-gutter)}
/* Top row: the logo on the left and the tagline on the right, vertically centred. The
   padding above the logo and the gap between logo and tagline are both --ft-logo-space
   (the logo's clear space, equal to its height). The space below the row, before the Our
   Locations heading, is --footer-logo-gap, which the client asked to be much tighter than
   the full clear space. On phones (media query at the end of this section) the logo and
   tagline stack and centre. */
.ft-top{display:flex;align-items:center;justify-content:space-between;gap:var(--ft-logo-space);padding-top:var(--ft-logo-space);padding-bottom:var(--footer-logo-gap)}
/* Footer logo: the same white icon logo file as the header
   (assets/img/logo/icon-white.svg). Its height is --logo-h, the SAME variable the header
   logo uses (96px on desktop, 80px at 980px wide and below), with width automatic, so the
   footer logo and the header logo are always exactly the same size. There is deliberately
   no max-width, max-height or fixed size here. flex:none stops it being squashed in the
   row. BRAND RULE: never recolour, stretch or add effects (shadow, glow, filter) to the
   logo. */
.ft-logo{display:block;width:max-content;flex:none}.ft-logo img{height:var(--logo-h);width:auto}
/* Tagline in the footer: Georgia, white, right-aligned beside the logo on desktop (centred
   under it on phones), 1.15rem. It is on TWO LINES, and the line break is in the markup,
   not left to the footer's width: the footer block in assets/js/main.js holds two spans,
   the first with Engineering expertise. Modern Living. and the second with Welcoming
   Hospitality. Inspired Style., with a normal space between them so that a screen reader
   reads one sentence. Each span is a block (display block), which puts it on its own line;
   text-wrap balance evens out a line if a narrow phone ever forces it to wrap inside
   itself. From 768px wide upwards each line is held on one line (white-space nowrap), and
   the box is at most 34rem wide; on narrower screens a line may wrap inside itself only if
   it truly cannot fit, so it never overflows. HOW TO CHANGE THE WORDING: edit the words
   inside the two spans in main.js (keep the full stops); to move the break, move words
   from one span to the other. The tagline is written once there, so it is identical on
   every page. */
#ft .tag{max-width:34rem;text-align:right;font:400 1.15rem/1.5 var(--g);color:#fff}
#ft .tag span{display:block;text-wrap:balance}
@media(min-width:768px){#ft .tag span{white-space:nowrap}}
/* HOME HERO TAGLINE ON ONE LINE (the paragraph with class tagline in the Home page hero;
   the footer tagline above is not part of this). WORDING: one sentence, held in two inline
   spans, its two halves: Engineering expertise. Modern Living. and Welcoming Hospitality.
   Inspired Style. HOW IT STAYS ON ONE LINE: each span is white-space nowrap, so the only
   place a line can ever break is the space between the two halves; so the tagline is ONE
   line wherever the screen is wide enough, and on a screen too narrow for that it wraps
   only between Modern Living. and Welcoming Hospitality., never inside a sentence
   (text-wrap balance keeps the halves even). The paragraph has no width limit, so nothing
   forces an early break. HOW BIG IT IS: font-size is clamp(smallest, a size worked out
   from the screen width, largest). The largest is 1rem, the size it has always had. The
   smallest is --tag-min (0.8125rem, 13px; change that one number to allow smaller or
   larger text). The size in between is the width of the hero's content divided by
   --tag-em, which is how many times its own font size the whole tagline is wide (about
   38.1 for Verdana, set to 40 here so that it fits with a little room to spare): the 90vw
   is the width of the hero's content (the screen less the side margins), so the tagline
   simply fills that width, then stops growing at its largest size. WHERE IT WRAPS: it
   stays on one line down to about 550px wide; below that the halves sit one above the
   other at its smallest size, each half still whole, and never overflows (the longer half
   is only about 245px wide at 13px). To make it wrap sooner or shrink less, change
   --tag-min or --tag-em. */
.tagline{--tag-min:.8125rem;text-wrap:balance}
.tagline span{white-space:nowrap}
.hero p.tagline{--tag-em:40;max-width:none;font-size:clamp(var(--tag-min),calc(90vw/var(--tag-em)),1rem)}
/* All footer paragraphs share one size and line height. The Our Locations heading keeps a
   small gap above the cards. */
#ft p{font-size:.82rem;line-height:var(--ft-lh)}
#ft h2{color:#fff;font-size:1.8rem;margin-bottom:1rem}
/* Our Locations grid, six equal columns. THE LIGHT BLOCK FIX: this grid has no background
   colour. An earlier version gave the grid a pale background that showed through every
   empty cell as a lighter blue block beside the last card; now the dividers are drawn on
   the cards themselves, so any unused space is simply the footer navy. Desktop (1024px and
   wider): the first three cards span 2 columns (a full row of three) and the last two span
   3 columns each (a full row of two), so both rows are always full. minmax(0,1fr) lets
   columns shrink instead of being pushed wider by long text. Gap between cards: --ft-gap. */
.locs{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:var(--ft-gap)}
/* Each location card: equal padding on all four sides (--ft-card-pad) and its own 1px
   hairline border, so cards never share a line and no line is doubled. min-width:0 and
   overflow-wrap:anywhere make long email addresses and addresses wrap inside the card
   instead of running past its edge. The texts themselves are not shortened. */
.locs article{min-width:0;padding:var(--ft-card-pad);border:1px solid rgba(255,255,255,.18);overflow-wrap:anywhere}
/* Column spans for the desktop layout. nth-child counts the cards in the order of the L
   list in main.js: cards 1 to 3 (Head Office, Marukab Plaza, Marukab Inn) span 2 columns,
   cards 4 and 5 (Urban Threads, CSR) span 3. */
.locs article:nth-child(-n+3){grid-column:span 2}.locs article:nth-child(n+4){grid-column:span 3}
/* Card text: small white title, with tight spacing between the lines inside a card. */
.locs h3{color:#fff;font-size:1.05rem;margin-bottom:.4rem}.locs p+p{margin-top:.25rem}
/* Applies to screens 1023px wide or narrower (tablets and phones). Two columns: every card
   takes one column (the spans are cancelled) and the last card (CSR) spans both columns,
   so the last row is full and there are no empty cells. The next rule, for screens 599px
   or narrower, switches to a single stacked column. */
@media(max-width:1023px){.locs{grid-template-columns:repeat(2,minmax(0,1fr))}.locs article:nth-child(-n+3),.locs article:nth-child(n+4){grid-column:auto}.locs article:last-child{grid-column:1/-1}}
@media(max-width:599px){.locs{grid-template-columns:minmax(0,1fr)}}
/* Get directions link: small uppercase text, underlined in white. It is as tall as
   --ft-tap (44px on phones) so it is easy to press; the text is centred in that height. */
#ft .dir{display:inline-flex;align-items:center;min-height:var(--ft-tap);margin-top:.25rem;font-size:.68rem;letter-spacing:.2em;text-transform:uppercase;text-decoration:underline;text-decoration-color:#fff;text-underline-offset:.35em}
/* Footer columns (quick links, business hours, social icons) side by side; they wrap on
   narrow screens (min() stops a column being wider than the screen). The quick links list
   is split into two columns so it is no taller than its neighbours. Each link is at least
   --ft-tap high. --ft-pad is the space above and below. */
.fcols{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:1.5rem 2rem;padding-block:var(--ft-pad)}
.fcols h3{margin-bottom:.75rem;font:400 .7rem var(--v);letter-spacing:.28em;text-transform:uppercase;color:#b7c3dc}
.fcols ul{columns:2;column-gap:1.5rem}.fcols li{list-style:none;break-inside:avoid}.fcols li a{display:flex;align-items:center;min-height:var(--ft-tap)}
/* Social icons: 44px outlined square buttons (a comfortable tap size) holding white line
   icons. */
.soc{display:flex;flex-wrap:wrap;gap:.8rem}.soc a{display:grid;place-items:center;width:44px;height:44px;border:1px solid rgba(255,255,255,.4)}
.soc svg{width:20px;height:20px;fill:none;stroke:#fff;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
/* Bottom bar: the copyright on the left and the Back to top button on the right, always on
   one line (the copyright text wraps if the screen is very narrow). The button is at least
   44px high to be easy to press. */
.fb{display:flex;justify-content:space-between;align-items:center;gap:1rem;padding-block:1rem;border-top:1px solid rgba(255,255,255,.18)}.fb p{min-width:0}
.top{display:inline-flex;align-items:center;flex:none;min-height:44px;padding:0 1.1rem;background:none;border:1px solid rgba(255,255,255,.45);color:#fff;font:400 .68rem var(--v);letter-spacing:.2em;text-transform:uppercase;cursor:pointer}.top:hover{background:#fff;color:var(--navy)}
/* Applies to screens 767px wide or narrower (phones): footer links grow to 44px high
   (--ft-tap), the space under the logo block becomes 1.1rem (--footer-logo-gap), and the
   logo row stacks and centres, with the logo's clear space kept between the logo and the
   tagline. */
@media(max-width:767px){#ft{--ft-tap:44px;--footer-logo-gap:1.1rem}.ft-top{flex-direction:column;gap:var(--ft-logo-space);text-align:center}#ft .tag{text-align:center}}
/* ========================================================================================
   SECTION 13: REDUCED MOTION
   Applies when the visitor has asked their device to reduce animation (an accessibility
   setting). All animations and transitions are switched off, smooth scrolling is turned
   off, scroll-reveal elements are shown straight away and the line drawing in the hero
   stays still. main.js also checks this setting.
   ======================================================================================== */
@media(prefers-reduced-motion:reduce){*,::before,::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}.rv{opacity:1;transform:none}.geo{transform:none!important}}
/* Small helpers: chip borders on dark sections, and .mt which adds 2rem of space above an
   element (used on many paragraphs and buttons). */
.dark .tags li{border-color:rgba(255,255,255,.6)}.mt{margin-top:2rem}

/* ========================================================================================
   SECTION 14: SMALL COMPONENTS
   Small standalone components used on individual pages: the external-link icon, text
   links, outline buttons, button groups, the Library logo, the headquarters slideshow,
   amenity icons, the Urban Threads Elaan section and contact form extras.
   ======================================================================================== *//* External-link icon: a small arrow beside links that open in a new tab. Screen readers
   get the words 'opens in a new tab' from an .sr span next to it. */
.ext{width:.78em;height:.78em;margin-left:.4em;flex:none;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
/* HOME PAGE INTRODUCTION: TEXT WITH THE NAVY LOGO (markup and notes in index.html, section
   ABOUT). THE VARIABLES, all set on .intro-grid: --lead-fs is the heading's font size (the
   same clamp as every h2); --intro-gap is the space between the two columns (clamp(2rem,
   5vw, 5rem)); --lead-measure (17) is how wide the heading's two halves need to be, in
   times the heading's font size (the longer half, A single standard of excellence., is
   about 16.2 times its font size, and 17 leaves a little room); --intro-text-min is the
   narrowest the text column may be: the larger of the paragraphs' normal line length
   (--measure-body) and the heading's need, so the paragraphs keep exactly their line
   length and the heading breaks only between its halves; --intro-logo-share (60%),
   --intro-logo-min (180px), --intro-logo-max (340px) and --intro-logo-maxw (70%) set the
   logo's height as a share of the text block's height with its limits, and its largest
   width as a share of its column; --intro-logo-trim lowers the top of the logo block to
   the tops of the heading's capital letters (the heading's line box starts a little above
   its capitals, about 0.2 times its font size; raise the number to start the logo lower,
   lower it to start higher). FROM 1024PX UP (one of the stylesheet's existing breakpoints; at
   861px the logo column would be only about 120px wide, too narrow for a logo of at least
   180px height; to start the grid at a smaller width, lower the 1024px in the media query
   below and check the logo still fits its column) the wrap block is a grid: the text column
   first (minmax(--intro-text-min, 7fr), so about 7 of 12 parts but never narrower than the
   minimum) then the logo column (5fr), with align-items stretch, which makes the logo
   block as tall as the text. In this block the logo is centred both ways with flex, at
   --intro-logo-share of the block's height (the block is as tall as the text, from the
   heading's capitals to the last paragraph's last line), limited as above, with its width
   following the file's proportions (width auto, object-fit contain, never stretched). It
   is shown at full strength: no opacity, filter, shadow, border or hover. The empty space
   around it is always more than the height of the M of its wordmark (about 6.7% of the
   logo's height) because the logo is only 60% of the text height and sits in the middle of
   its column with at least the gap to the text. THE HEADING: from 1024px up the two halves
   (class lead-half) are inline blocks, so each stays on one line, and the heading is
   balanced, so it reads as two lines and never ends a line with the single letter A; below
   1024px the halves are ordinary text and the heading wraps as before. BELOW 1024PX the
   section stacks as before and the logo block is hidden (display none, which also removes
   it from screen readers); to show a slim centred logo there instead, replace the none by
   flex and give the img a height of clamp(5rem, 22vw, 8rem). The classes only exist on the
   Home page. */
.lead-st{max-width:24ch}.intro{margin-top:2.4rem}
.intro-grid{--lead-fs:clamp(1.9rem,3.8vw,3.3rem);--lead-measure:17;--intro-gap:clamp(2rem,5vw,5rem);--intro-text-min:max(var(--measure-body),calc(var(--lead-fs)*var(--lead-measure)));--intro-logo-share:60%;--intro-logo-min:180px;--intro-logo-max:340px;--intro-logo-maxw:70%;--intro-logo-trim:calc(var(--lead-fs)*.2)}
.intro-grid .lead-st{font-size:var(--lead-fs)}
.intro-logo{display:none}
@media(min-width:1024px){
.intro-grid{display:grid;grid-template-columns:minmax(var(--intro-text-min),7fr) minmax(0,5fr);column-gap:var(--intro-gap);align-items:stretch}
.intro-grid .lead-st{text-wrap:balance}
.lead-half{display:inline-block}
.intro-logo{display:flex;align-items:center;justify-content:center;padding-top:var(--intro-logo-trim)}
.intro-logo img{display:block;width:auto;height:clamp(var(--intro-logo-min),var(--intro-logo-share),var(--intro-logo-max));max-width:var(--intro-logo-maxw);object-fit:contain}
}
/* Text link (class tl): a bold underlined link inside a paragraph, for example a call to
   action at the end of a sentence. */
a.tl{font-weight:700;text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:4px}a.tl:hover{text-decoration-thickness:4px}
/* Outline button variant (class o, used together with btn): transparent with navy text and
   filled navy on hover. */
.btn.o{background:transparent;color:var(--navy)}.btn.o:hover{background:var(--navy);color:#fff}
/* Button group: buttons side by side with a gap. Below 560px (next rule) they stack and
   centre their text. */
.btns{display:flex;flex-wrap:wrap;gap:1rem;margin-top:2.4rem}
@media(max-width:560px){.btns{flex-direction:column}.btns .btn{text-align:center}}
/* The Library logo image: 140px wide in the home page teaser; class lg allows up to 300px
   in the CSR page intro. Show it exactly as supplied with plenty of clear space; never
   recolour or distort it. */
.libl{display:block;width:140px;height:auto;margin-bottom:2rem}.libl.lg{width:min(100%,300px);margin:0}
/* HEADQUARTERS SLIDESHOW (home page). .slides is a square frame (aspect-ratio:1/1) so the
   layout never jumps between photos. Every .slide is stacked on top of the others
   (position:absolute) and invisible; the slide with class on is visible. Changing opacity
   over 0.7 seconds gives the crossfade. The 3 second timing, and when the slideshow pauses
   (while a mouse is over it and while keyboard focus is on a dot) and resumes, are in main.js,
   not here. .ctl is the row under the photos, with the dots centred in it, and .sdots holds
   the indicator dots; each dot is 44px, a comfortable tap size. */
.slides{position:relative;aspect-ratio:1/1;overflow:hidden;background:var(--navy-m)}
.slide{position:absolute;inset:0;opacity:0;transition:opacity .7s ease}.slide.on{opacity:1}.slide img{width:100%;height:100%;object-fit:cover}
.ctl{display:flex;align-items:center;justify-content:center;gap:1rem;margin-top:1rem}
.sdots{display:flex}.sdots button{display:grid;place-items:center;width:44px;height:44px;background:none;border:0;cursor:pointer}
.sdots button::before{content:"";width:11px;height:11px;border:1px solid var(--navy);transform:rotate(45deg)}.sdots button[aria-current]::before{background:var(--navy)}
/* Amenity icons (Marukab Inn): 24px navy line icons with one consistent stroke weight. The
   next rule lays each amenity out as icon plus text with even spacing and lets the text
   wrap on small screens. */
.ic{width:24px;height:24px;flex:none;fill:none;stroke:var(--navy);stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.cols li{display:flex;align-items:center;gap:1.15rem;padding:.9rem 0}.cols li span{flex:1;min-width:0}
/* URBAN THREADS: ELAAN SECTION. The brand mauve is the variable --urban-mauve (section 1).
   It is used only on the Urban Threads page: as this section's background and as text
   colour on chosen headings and paragraphs (class um, last rule). The section has two
   halves of equal width: the LOGO WINDOW (.emb, white because the supplied animation has a
   pure white background) and the Elaan text (.mvc, white text). THE HEIGHT comes only from
   the text: the text block plus the padding variable --elaan-pad above and below it
   (clamp(2.5rem, 5vw, 5.5rem): 40px on phones, growing to 88px on wide screens; change it
   to make the section taller or shorter, the text stays exactly in the middle because the
   padding is the same above and below). The window holds nothing that takes up room (the
   logo frame is positioned inside it), so it is stretched to the height of the text half
   and nothing else sets the height; there is no minimum height and no height in screen
   units, and the video's size can never change the layout. THE LOGO WINDOW CROPS THE
   ANIMATION: the animation and its static poster are a tall white frame, 1080 by 1920
   pixels, with the logo drawn near the middle of it. The rule on .emb video and .emb
   .emb-s lays that frame inside the window: its top-left corner is put at the centre of
   the window (left 50%, top 50%) and it is then moved back by --logo-cx and --logo-cy,
   which are where the centre of the logo sits inside the frame as a percentage of the
   frame (51.1% across and 46.9% down, measured on the animation's final frame), so the
   logo's centre lands in the exact centre of the window whatever the window's size. The
   window clips (overflow clip) everything outside it, which is only the frame's plain
   white margin, white like the window, so no edge or seam shows. THE SIZE of the frame is
   --frame-w. On desktop it is at most --frame-max (380px) and never wider than the window
   less the side space --logo-side-pad, which keeps the logo the size it always had (about
   197 by 88px at 380px); the logo is --logo-wr (0.5185) of the frame's width wide and
   --logo-hr (0.2306) of the frame's width tall, which is how the stacked rules below work
   out its size. THE NUDGE: --logo-nudge-x and --logo-nudge-y (both 0px) move the logo by
   that many pixels, right and down when positive, left and up when negative. THE STATIC
   LOGO: the poster that the video element shows before it plays and without JavaScript,
   and the picture main.js swaps in for reduced motion or a failed download (class emb-s),
   follow the same rule with the same variables as the video, and the poster has the same
   artwork in the same place as the animation's last frame, so nothing jumps when the
   animation starts, loops or ends. STACKED LAYOUT (860px wide or narrower): the halves
   stack with the window first. There the logo is --logo-share (0.6, that is 60%) of the
   window's width but never more than --logo-cap (246px), so --frame-w is that logo width
   divided by --logo-wr; the window's height is --stack-x (2.4) times the logo's height,
   set with an aspect ratio and a matching maximum height so that it does not depend on the
   video (the window always keeps the full width of the screen, which is why it also has width
   100%: without it a browser would narrow the window to fit the capped height and show a strip
   of mauve beside it), and the logo is centred in it with the same space above and below. The
   text then
   follows with the padding --elaan-pad above and below. The logo is only ever scaled
   evenly. */
.mv{--elaan-pad:clamp(2.5rem,5vw,5.5rem);--logo-cx:51.1%;--logo-cy:46.9%;--logo-nudge-x:0px;--logo-nudge-y:0px;--logo-wr:.5185;--logo-hr:.2306;--frame-max:380px;--logo-side-pad:clamp(2.5rem,6vw,5rem);--logo-share:.6;--logo-cap:246px;--stack-x:2.4;--frame-w:min(var(--frame-max),calc(100% - 2*var(--logo-side-pad)));display:grid;grid-template-columns:1fr 1fr;padding:0;background:var(--urban-mauve);color:#fff}
.mv .eb,.mv h2{color:#fff}
.mv .emb{position:relative;overflow:hidden;overflow:clip;background:#fff}
.emb video,.emb .emb-s{position:absolute;left:50%;top:50%;display:block;width:var(--frame-w);max-width:none;height:auto;aspect-ratio:9/16;transform:translate(calc(-1*var(--logo-cx) + var(--logo-nudge-x)),calc(-1*var(--logo-cy) + var(--logo-nudge-y)))}
/* The text half: the label, heading and paragraph in one column, centred vertically in the
   section, with the padding --elaan-pad above and below and the usual space at the sides. */
.mv .mvc{display:flex;flex-direction:column;justify-content:center;padding:var(--elaan-pad) clamp(1.4rem,6vw,5rem)}
/* Applies to screens 860px wide or narrower: the two halves stack, the logo window first. */
@media(max-width:860px){
.mv{grid-template-columns:1fr;--frame-w:min(calc(var(--logo-share)/var(--logo-wr)*100%),calc(var(--logo-cap)/var(--logo-wr)))}
.mv .emb{width:100%;aspect-ratio:1/calc(var(--stack-x)*var(--logo-hr)*var(--logo-share)/var(--logo-wr));max-height:calc(var(--stack-x)*var(--logo-cap)*var(--logo-hr)/var(--logo-wr))}
}
/* Contact form error state: when the message box is empty on submit, main.js sets
   aria-invalid on it, which gives it a thicker navy border. .err styles the message shown
   under it (navy with a bar on the left; no red because the brand palette has none). */
textarea[aria-invalid="true"]{border:2px solid var(--navy)}
.err{padding-left:.8rem;border-left:3px solid var(--navy);color:var(--navy);font-weight:700}
/* Makes the destination email address under the contact form easy to copy: one click
   selects all of it. */
.cp{user-select:all}
/* Mauve text (Urban Threads page only): colours the headings and paragraphs marked with
   class um using the shared --urban-mauve variable. */
.um{color:var(--urban-mauve)}
/* ========================================================================================
   SECTION 15: INSTAGRAM FEED SECTIONS (CSR page and Urban Threads page)
   A text panel and a live Instagram feed card. Colours come from the existing palette
   only: the CSR page uses the navy band (class dark) with a white card; the Urban
   Threads page uses a light section with the shared urban-mauve accents (class ig-um:
   heading, button fill and a thin top rule). The button text on mauve is navy (contrast
   5.1 to 1). Stacked and centred below 1024px; two columns from 1024px (text about 40
   percent, card about 60 percent). The feed height is the ig-embed-h variable. Motion
   (shimmer, fade-in, scroll reveal) is switched off by the reduced-motion rules in
   section 13.
   ======================================================================================== */
/* Layout: one centred column (stacked, text first) on tablet and phone; minmax(0,1fr) lets
   the column shrink so nothing overflows at 320px. From 1024px (the media query below) it
   becomes two columns, 2fr and 3fr (40 and 60 percent), vertically centred. */
.ig-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(2rem,5vw,3rem);justify-items:center;align-items:center}
.ig-text{min-width:0;text-align:center}
/* Eyebrow with the Instagram icon beside it (the same drawing as the footer social icon,
   coloured by the surrounding text). The handle line is Verdana with wide letter-spacing;
   it is a div, not a paragraph, so it keeps its own style. */
.ig-eb{display:flex;align-items:center;justify-content:center;gap:.6rem}
.ig-ico{width:1.2em;height:1.2em;flex:none;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.ig-text h2{margin-bottom:.9rem}
.ig-handle{font:400 .95rem/1.5 var(--v);letter-spacing:.18em;margin-bottom:1.8rem;overflow-wrap:anywhere}
/* The feed card: rounded corners (18px) with overflow hidden, a thin border in the subtle
   line colour, a soft shadow, a maximum width of 540px and its height reserved from
   --ig-embed-h so nothing jumps while the feed loads. position:relative lets the skeleton,
   iframe and fallback card sit on top of each other inside it. */
.ig-card{position:relative;width:100%;max-width:540px;min-width:0;height:var(--ig-embed-h);border-radius:18px;overflow:hidden;background:#fff;border:1px solid var(--line);box-shadow:0 14px 40px rgba(10,22,48,.14)}
/* Applies from 1024px wide: two columns (40 and 60 percent), text left-aligned, card
   centred in its column. */
@media(min-width:1024px){.ig-grid{grid-template-columns:minmax(0,2fr) minmax(0,3fr);justify-items:stretch}.ig-text{text-align:left}.ig-eb{justify-content:flex-start}.ig-card{justify-self:center}}
/* Loading skeleton: a soft shimmer built from two existing palette tints, the same shape
   as the card (it fills it). The shimmer is the animation named igs; reduced motion stops
   it so it is a still shape. */
.ig-skel{position:absolute;inset:0;background:linear-gradient(100deg,var(--tint) 30%,var(--off) 50%,var(--tint) 70%);background-size:220% 100%;animation:igs 1.8s linear infinite}
@keyframes igs{from{background-position:120% 0}to{background-position:-120% 0}}
/* The feed iframe: fills the card, no border, white background, invisible until its load
   event fires (main.js then adds is-loaded) and then fades in over 0.6s. Without
   JavaScript (card has no is-js class) the skeleton and the empty iframe are hidden so
   only the noscript fallback card shows. */
.ig-if{position:absolute;inset:0;width:100%;height:100%;min-width:0;border:0;background:#fff;opacity:0;transition:opacity .6s ease}
.ig-card:not(.is-js) .ig-skel,.ig-card:not(.is-js) .ig-if{display:none}
.ig-card.is-loaded .ig-if{opacity:1}
.ig-card.is-loaded .ig-skel{opacity:0;visibility:hidden;transition:opacity .6s ease,visibility 0s .6s}
/* Fallback card inside the same frame: white with the icon, handle and a View on Instagram
   button, centred. It shows when main.js adds is-failed (feed not loaded after the wait
   time) and always inside noscript (ig-fb-ns); it hides again if the feed loads later
   (is-loaded). The button inside it is navy on white on both pages (these rules beat the
   white button used on the navy band), and its focus ring is navy. */
.ig-fb{position:absolute;inset:0;z-index:2;display:none;flex-direction:column;align-items:center;justify-content:center;gap:1rem;padding:2rem;text-align:center;background:#fff;color:var(--navy)}
.ig-card.is-failed .ig-fb,.ig-fb-ns{display:flex}
.ig-card.is-loaded .ig-fb{display:none}
.ig-fb .ig-ico{width:2.6rem;height:2.6rem}
.ig-fb .ig-handle{margin:0;color:var(--navy)}
.ig-card .ig-fb .btn{background:var(--navy);color:#fff;border-color:var(--navy)}
.ig-card .ig-fb .btn:hover{background:#fff;color:var(--navy)}
.ig-fb :focus-visible{outline-color:var(--navy-m)}
/* Urban Threads version: a thin mauve rule along the top of the section and a mauve Follow
   button with navy text (navy on mauve is 5.1 to 1 contrast); on hover it turns white. The
   heading is mauve through class um. Navy band version: a thin white-tint line along the
   bottom so the band does not melt into the navy footer below it. */
.ig-um{border-top:1px solid var(--urban-mauve)}
.ig-um .btn{background:var(--urban-mauve);border-color:var(--urban-mauve);color:var(--navy)}
.ig-um .btn:hover{background:#fff;color:var(--navy)}
.dark.ig{border-bottom:1px solid rgba(255,255,255,.18)}
/* ========================================================================================
   SECTION 16: PHOTO LAYOUTS FOR THE RESIDENTIAL AND CSR PAGES
   Banner photo positions (object-position: across down) for the page banners: pos-res
   (Residential and Portfolio banners, which show the same photo: 50% across and 72% down on
   desktop keeps the yellow building in
   the wide band; 22% across on phones up to 700px keeps it centred in the narrow crop),
   pos-csr (CSR banner: three variables hold its focal
   point, see the CSR block below). Change the percentages to reframe; 0% is the
   left or top edge and 100% the right or bottom edge. Gallery layouts: g3 is for 3 photos (no
   page uses it at the moment) and g5 for 5 photos (Residential page); the Ongoing Projects
   page has its own square gallery, gsq, in section 21. The lightbox counter
   (class cnt) is the small 3 / 9 style number at the top of the lightbox.
   ======================================================================================== */
.pos-res{object-position:50% 72%}
@media(max-width:700px){.pos-res{object-position:22% 50%}}
/* CSR PAGE HEADER PHOTO (class pos-csr, used by the banner image in csr.html). The photo
   is a tall portrait shown in a wide band, so only a slice of it is visible, and the slice
   depends on the screen. THREE VARIABLES hold the focal point, one per screen size, each
   an object-position value (across then down): --csr-hero-pos-desktop for screens 981px
   wide and up, --csr-hero-pos-tablet for 600px to 980px, and --csr-hero-pos-mobile for
   599px and narrower. The first number moves the photo sideways (it has no effect while
   the photo fills the full width, which is the usual case), and the second moves the
   visible slice up or down: 0% shows the top of the photo, 100% the bottom. They are set
   so the hand taking a book from the shelf, with the book, stays in view. TO NUDGE THE
   CROP: change only the second number in the variable for that screen size (a smaller
   number shows more of the top, such as the shelf above the hand; a larger number shows
   more of the person and the aisle below), save, and check the page at that size. The
   photo file, the hero height, the overlay and the heading are not touched by this. */
:root{--csr-hero-pos-desktop:50% 26%;--csr-hero-pos-tablet:50% 19%;--csr-hero-pos-mobile:50% 36%}
.pos-csr{object-position:var(--csr-hero-pos-desktop)}
@media(max-width:980px){.pos-csr{object-position:var(--csr-hero-pos-tablet)}}
@media(max-width:599px){.pos-csr{object-position:var(--csr-hero-pos-mobile)}}
/* Gallery g3 (3 photos): 3 equal square tiles in one row from 600px wide. Below 600px: 2
   columns with the first tile spanning both (4 by 3) and the other two beside each other,
   so there are never empty cells. The tiles crop the photo (object-fit:cover), the lightbox
   shows it whole. No page uses this layout at the moment; it is kept ready for a three photo
   gallery. */
.gal.g3{grid-template-columns:repeat(3,minmax(0,1fr))}.gal.g3 button{aspect-ratio:1/1}
/* Gallery g5 (5 photos): from 600px wide a 6-column grid in which tiles 1 to 3 take 2
   columns each and tiles 4 and 5 take 3 columns each, so both rows are full. Every tile
   has the same fixed height (grid-auto-rows, between 240px and 420px depending on the
   screen width), so the two rows look deliberate. Below 600px (next rule): 2 columns, the
   first tile spans both, the other four make 2 rows of 2, and the rows are 180px to 260px
   high. */
.gal.g5{grid-template-columns:repeat(6,minmax(0,1fr));grid-auto-rows:clamp(240px,32vw,420px)}
.gal.g5 button{height:100%;aspect-ratio:auto}
.gal.g5 button:nth-child(-n+3){grid-column:span 2}.gal.g5 button:nth-child(n+4){grid-column:span 3}
@media(max-width:599px){.gal.g3{grid-template-columns:repeat(2,minmax(0,1fr))}.gal.g3 button:first-child{grid-column:1/-1;aspect-ratio:4/3}
.gal.g5{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:clamp(180px,48vw,260px)}
.gal.g5 button:nth-child(-n+3),.gal.g5 button:nth-child(n+4){grid-column:auto}.gal.g5 button:first-child{grid-column:1/-1}}
/* Lightbox counter: a small centred number such as 3 / 9 at the top of the lightbox, in
   the lightbox's light text colour. main.js fills it with the number of the open photo and
   the total number of photos in the gallery. */
.lb .cnt{position:absolute;top:1.6rem;left:50%;transform:translateX(-50%);color:#dbe3f1;font:400 .8rem var(--v);letter-spacing:.14em}
/* ========================================================================================
   SECTION 17: HOME PAGE CSR TEASER PHOTO (SHOWN WHOLE)
   The photo in the Library teaser on the Home page (csr-home.jpg, a tall portrait of
   hands holding two books beside coffee) is deliberately shown WHOLE, so both books are
   visible and nothing is cropped on any side. It does not sit in a .ph photo box like
   the other photos, because those boxes force a fixed shape and fill it by cropping; it
   has its own wrapper, class csr-teaser, and the image has class csr-teaser-photo. These
   two classes are used by this one photo only, so no other picture on the site is
   affected. THE RULE THAT KEEPS IT UNCROPPED: the image keeps its own true shape (its
   width and height attributes give the proportions and the CSS sets height auto, never a
   fixed shape), is never wider than its column (max-width 100%) and never taller than
   the variable below, and object-fit contain with object-position center is a safety net
   so that no part could ever be clipped. When the height limit applies, the whole photo
   simply becomes smaller and is centred in its column. THE ONE VARIABLE:
   --csr-photo-max-h (set on .csr-teaser) is the maximum height of the photo. The
   default, min(80vh,640px), means 80 percent of the screen height or 640 pixels,
   whichever is smaller; raise it for a bigger photo or lower it for a smaller one, and
   the photo's shape never changes. Nothing sits on top of the photo, there is no
   clip-path or mask, and no rounded corners or shadow are applied at rest (this slot had
   none). The old zoom on hover, which enlarged the picture inside a clipped box, is
   replaced by a lift of 4px with a soft navy shadow, which crops nothing. The wrapper
   keeps class rv, the site's scroll-reveal fade-in, which reduced motion switches off.
   The text beside the photo is centred against it by the existing split layout.
   ======================================================================================== */
.csr-teaser{--csr-photo-max-h:min(80vh,640px)}
/* The photo itself: display block with automatic side margins centres it in its column
   when the height limit makes it narrower than the column. width auto and height auto keep
   its natural shape, max-width 100% stops it overflowing a narrow screen, and max-height
   uses the variable. The transition lets the lift on hover glide. */
.csr-teaser-photo{display:block;width:auto;max-width:100%;height:auto;max-height:var(--csr-photo-max-h);margin:0 auto;object-fit:contain;object-position:center;transition:transform .4s ease,box-shadow .4s ease}
.csr-teaser-photo:hover{transform:translateY(-4px);box-shadow:0 14px 30px rgba(10,22,48,.18)}
/* ========================================================================================
   SECTION 18: HOME PAGE BRAND LOGO STRIP (ENDLESS MARQUEE)
   The band of five brand logos directly above the closing call-to-action band on the
   Home page (markup in index.html, behaviour in main.js, section BRAND LOGO STRIP). THE
   VARIABLES, all set on .brands just below, are the only things you normally change:
   --logo-strip-h is the height every logo is drawn at (44px on phones growing to 64px,
   so about 64px on a 1280px screen); --logo-strip-gap is the space between logos (3rem
   on phones up to 6.5rem); --logo-strip-pad is the space above and below the row (3rem
   to 5rem, the same above and below, so the row is centred in the band);
   --logo-strip-speed is how fast the row moves, in pixels per second (50, or 40 on
   phones, and the same whatever the screen width or the number of logos);
   --logo-strip-bg is the band colour (solid white, so logo files with a flat white
   background blend in invisibly; if the sections above and below were both white, the
   existing off-white would be used instead). Each logo has its own size multiplier
   --logo-scale, set by the class on its list item (b-marukab, b-plaza, b-figolive,
   b-urban and b-library, defined below), which makes the five look equally heavy: square
   or stacked marks look bigger than wide wordmarks at the same height, so they are tuned
   by eye; a logo without its own class uses 1. The width of a logo follows its own shape
   (width auto) and never goes above 200px. SPACING: the gap is a right margin on each
   logo (margin-inline-end), not the flex gap property, so that every copy of the list is
   exactly the same width and the loop has no jump. TWO LOOKS: (1) the still look, which
   is also what shows without JavaScript, with reduced motion, or while a logo has
   keyboard focus: one centred row that wraps onto more lines if needed, with no copies;
   (2) the moving look, switched on by main.js with the class live: main.js moves the
   list into a track, adds copies, and sets two values on the track (--brands-dist, the
   exact width of one half of the track in pixels as a negative number, and --brands-dur,
   that width divided by the speed). The track slides left by exactly that distance in an
   endless straight-line animation (transform only), and because the second half of the
   track is an exact copy of the first, the picture at the end of each cycle is identical
   to the picture at the start, so the loop never jumps. The band uses overflow clip so
   the moving row can never create sideways scrolling of the page. Nothing sits on top of
   the logos, and no fade, mask, blur or clip-path touches them; they glide off both
   edges of the window. WHEN IT PAUSES: main.js adds the class halt to the band while a
   mouse is over any part of the band (only on devices with a real mouse), while a finger
   or pen is held down on the band, and while the band is off-screen; the CSS then
   freezes the animation where it is (animation-play-state paused, so the position is
   kept). WHEN IT RESUMES: it carries on from the same position at the same speed when
   the class halt is removed, that is when the mouse leaves, the finger is lifted or the
   press becomes a scroll, or the band comes back into view. Nothing changes visibly on
   hover.
   ======================================================================================== */
.brands{--logo-strip-h:clamp(44px,5vw,64px);--logo-strip-gap:clamp(3rem,6vw,6.5rem);--logo-strip-pad:clamp(3rem,6vw,5rem);--logo-strip-speed:50;--logo-strip-bg:#ffffff;position:relative;overflow:hidden;overflow:clip;padding-block:var(--logo-strip-pad);background:var(--logo-strip-bg)}
@media(max-width:600px){.brands{--logo-strip-speed:40}}
/* The list in its still look (and without JavaScript): a centred row that wraps. Every
   item has its space on its right side, so the list gets the same amount of padding on its
   left to keep the logos visually centred, including on wrapped rows. In the moving look
   (class live) the padding is removed so that each copy of the list has exactly the same
   width. */
.brands-list{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;margin:0;padding:0 0 0 var(--logo-strip-gap);list-style:none}
.brand{display:flex;align-items:center;margin-inline-end:var(--logo-strip-gap)}.brand[hidden]{display:none}
.brands:not(.live) .brand{margin-block:.9rem}
.brand a{display:block;line-height:0}
/* A logo image: drawn at the shared height times its own multiplier, width following its
   shape, never wider than 200px, never filtered, faded, scaled or glowing (there is no
   hover effect on a logo; only links show the pointer). The four multipliers below were
   tuned by looking at the result: the Marukab mark is a tall stacked mark and gets the largest
   multiplier (see the note just above its rule); the Marukab Plaza and Fig and Olive logos are
   stacked marks
   with lettering below; the Urban Threads logo is a wide wordmark and needs the least; The
   Library logo is a square badge whose dark square is part of the logo; its multiplier is set
   so that its visible width equals the median visible width of the other four logos
   (b-library, see the note below). If
   you add a logo, give its li a class of its own with a --logo-scale value, or leave it at
   1. */
.brand img{display:block;width:auto;height:calc(var(--logo-strip-h) * var(--logo-scale,1));max-width:200px;object-fit:contain}
/* THE MARUKAB MULTIPLIER lives in this one rule: b-marukab sets --logo-scale to 1.8. The
   Marukab logo is a stacked mark (the sails above the lettering), which is narrow, so at
   the same height as the wide wordmarks it carries far less visual weight; 1.8 makes its
   visible artwork about 1.2 times as tall as the tallest other logo (the limit is 1.25
   times) at every screen width, because all logos scale together with --logo-strip-h. To
   make it bigger or smaller change only this number (about 0.05 changes its height by 3
   percent), then check that its height stays between 1 and 1.25 times the tallest other
   logo and that nothing is clipped; the row simply grows to fit the tallest logo and every
   logo stays vertically centred in it. The file assets/img/logo/marukab-logo-navy.svg is a
   copy of the supplied artwork with no frame and only a very small margin (about 1.5 percent),
   trimmed tightly to the
   sails, base line and lettering, so the multiplier scales only the logo itself: if a
   frame or margin were ever put back in that file, the logo would look smaller and show a
   box. The other three multipliers below are unchanged. */
.b-marukab{--logo-scale:1.8}.b-plaza{--logo-scale:1.45}.b-figolive{--logo-scale:1.35}/* THE LIBRARY LOGO'S WIDTH: b-library (written with a class on its list item, so it does
   not depend on the logo's position in the list, which changes in the script-made copies)
   holds its own size multiplier, logo-scale, set to 1.81. The Library file is a square
   whose dark square fills its whole picture (no empty margin to trim), and it is sized by
   height like the others (width auto, so the box hugs the artwork), so its visible width
   is the logo height times this number. It was set by measuring the visible artwork of all
   five logos at 1280px: the target is the median of the visible widths of the other four
   (Marukab, Marukab Plaza, Fig and Olive, Urban Threads), which is the average of the
   middle two, about 116px, and all five logos scale together with the logo height
   variable, so the match holds at every screen width. To make the logo wider or narrower
   change only this number (adding 0.1 widens it by about 6px at desktop size); keep its
   height within 1.25 times the tallest other logo. The other four multipliers are not
   touched. The 200px maximum width that all logos share is not reached by this logo. */
.b-urban{--logo-scale:1}.b-library{--logo-scale:1.81}
/* The moving look. The track is as wide as all its copies (width max-content) and is the
   only thing that is animated, by transform alone, with will-change so the browser moves
   it on the graphics card. The keyframes slide it from 0 to --brands-dist (negative, set
   by main.js). Each list is flex none, so no list is squeezed. The class halt, added and
   removed only by main.js (see the section banner above for exactly when), freezes the
   animation in place and lets it carry on from the same position. */
.brands.live .brands-track{display:flex;width:max-content;will-change:transform;animation:brands-scroll var(--brands-dur,60s) linear infinite}
.brands.live .brands-list{flex:none;flex-wrap:nowrap;justify-content:flex-start;padding:0}
@keyframes brands-scroll{from{transform:translateX(0)}to{transform:translateX(var(--brands-dist,0px))}}
.brands.halt .brands-track{animation-play-state:paused}
/* Reduced motion: no animation at all. Whatever main.js does, the strip stays in its still
   look: one centred, wrapping row of the original logos with the same gap and sizes, and
   the copies are hidden. */
@media(prefers-reduced-motion:reduce){.brands .brands-track{display:block;width:auto;animation:none;transform:none}.brands .brands-clone{display:none}.brands .brands-list{flex-wrap:wrap;justify-content:center;padding:0 0 0 var(--logo-strip-gap)}}
/* SECTION 21: ONGOING PROJECTS PAGE (the markup and the notes on adding a project or
   replacing a photo are in ongoing-projects.html). THE BREAKPOINT: everything below
   changes at 861px wide, the same width at which the site's other two-column blocks stack
   (the split rule); below it the blocks stack in the order they are written. INTRODUCTION
   AND INDEX (pj-top): ONE grid row. Below 861px it is one column (the introduction, then
   the index, both full width, no alignment) with the gap clamp(2rem, 5vw, 5rem). From
   861px it has two columns, minmax(0, 7fr) and minmax(0, 5fr), which is about 7 and 5 of
   12 parts, with the same gap. The introduction (pj-intro) is on the left, with the site's
   normal h2 heading. The index (pj-index) is on the right, pushed to the container's right
   edge by justify-self end and at most 520px wide. THE LAST-LINE ALIGNMENT: inside a test
   for browser support (at-supports), the grid uses align-items last baseline, which makes
   the baseline of the LAST text line of each column sit on the same horizontal line: the
   last line of the introduction paragraph (the line that holds the link) and the text of
   the index's last row. The shorter column is moved down to meet the longer one, so the
   empty space is above the index, beside the heading, and the two columns end together. No
   script and no fixed heights are used, so it holds when the paragraph wraps onto two,
   three or more lines at other widths. THE FALLBACK, for a browser that does not
   understand last baseline: align-items end (the bottoms of the two columns level) plus
   the variable index-baseline-offset, a length in rem defined on pj-top, which moves the
   index down by that amount (position relative and top) so that the baselines still meet.
   Its value is the difference between two distances: from the paragraph's last baseline to
   the bottom of the paragraph, and from the baseline of the index's last row to the bottom
   of the index. If you change the paragraph's font size or line height, or the height of
   an index row, measure again and change that one number (a larger number moves the index
   lower). THE INDEX is an ordered list whose default numbers are switched off; the numbers
   1 and 2 are drawn by the counter pj in a ::before in Georgia and navy, so each link
   contains only the project name and place (the b tag is Georgia Bold, the place regular
   weight). Each row is at least 44px high with a thin line above it (and the last row one
   below); hovering a row shows a subtle navy tint, and the text colour and underline do
   not change; the link keeps the site's keyboard focus ring. PROJECT BANDS (pj-band, one
   section per project): the vertical padding is clamp(3rem, 7vw, 6rem). THE COLOURS come
   from two variables defined on pj-band: band-bg (the background) and band-fg (the colour
   of the heading and the line under it). The default is a NAVY band: band-bg is the brand
   navy variable (the same navy as the header and footer) and band-fg is white; such a band
   also carries the class dark, which supplies the white keyboard focus ring and the light
   navy tint of the label. The extra class pj-band-light makes a WHITE band: band-bg is
   white (#ffffff) and band-fg is the brand navy; on a white band the keyboard focus ring
   is a 2px navy outline with a 2px offset. To change a band's colour, add or remove
   pj-band-light (and dark) on its section in the HTML. Navy on white and white on navy are
   both about 16 to 1, well above the 4.5 to 1 needed; the label on the navy band uses the
   site's shared eyebrow tint, about 9 to 1. DIVIDERS: no line between the navy Hiya band
   and the white Beach band; a thin 1px line in the page's light line variable along the top
   of the gallery (class pj-gallery), so that the white Beach band does not run into it. THE
   LABEL (Hiya band only) is the
   site's shared eyebrow (class eb): small, tracked, uppercase Verdana in the light navy
   tint, with the shared gap below it. Each band is a grid (band-grid): one column below
   861px (the text, then the photo at full width) and, from 861px, two columns minmax(0,
   5fr) and minmax(0, 7fr), which is about 5 and 7 of 12 parts, with the gap clamp(2rem,
   5vw, 5rem) and the text vertically centred against the photo. The band heading is
   Georgia Bold, clamp(2rem, 4vw, 3.25rem); the line under it (band-line) is Georgia
   Regular, clamp(1.15rem, 1.6vw, 1.5rem). THE PHOTO FRAME (band-media) is always a square
   (aspect-ratio 1 by 1): full width of the container when stacked, and from 861px at most
   560px wide, against the container's right edge. The photo button (class ph, which
   supplies the clipping and the zoom on hover) fills it, and the img inside is cropped to
   the square by object-fit cover (its focal point is the object-position in the img's
   style attribute). THE LOOK OF THE FRAMES: the variables pj-radius (corner radius) and
   pj-shadow (shadow), defined on the bands and the gallery, are 0 and none because the
   site's photos have square corners and no shadow; for example 12px and 0 6px 18px
   rgba(15,32,67,.12) would round the corners and add a soft shadow, which looks right on
   the white bands, to every photo frame at once. THE GALLERY (gal gsq): uniform square tiles,
   object-fit cover, in two columns from 600px wide and one column below, so no cell is ever
   empty. The gap is the variable gal-gap (1rem, the site's usual gallery gap). The grid is
   centred on the page (equal automatic side margins) and is at most two tiles plus the gap
   wide, where a tile is limited by the variable gallery-tile-max (560px); both variables are
   on the gal gsq rule and are written with two leading hyphens. To make the two tiles share
   the container's full width, set gallery-tile-max to 1000px. The tiles use the same variables
   as the project photos for corners and shadow. To
   change a breakpoint change 861px or 599px below. */
.pj-top{--index-baseline-offset:0.66rem;display:grid;gap:clamp(2rem,5vw,5rem)}
.pj-intro h2{text-wrap:balance;hyphens:none;overflow-wrap:normal;word-break:normal}
.pj-index ol{list-style:none;margin:0;padding:0;counter-reset:pj}
.pj-index li{counter-increment:pj;display:flex;align-items:center;border-top:1px solid var(--line);transition:background .25s ease}
.pj-index li:last-child{border-bottom:1px solid var(--line)}
.pj-index li:hover{background:rgba(15,32,67,.06)}
.pj-index li::before{content:counter(pj);flex:none;width:2.2rem;padding-left:.5rem;font:400 1.05rem/1 var(--g);color:var(--navy)}
.pj-index a{flex:1;display:flex;align-items:center;min-height:44px;padding:.75rem .5rem;font:400 1.05rem/1.3 var(--g);color:var(--navy);text-decoration:none}
.pj-index a b{font-weight:700}
.pj-band,.gal.gsq{--pj-radius:0;--pj-shadow:none}
.pj-band{--band-bg:var(--navy);--band-fg:#fff;background:var(--band-bg);padding-block:clamp(3rem,7vw,6rem)}
.pj-band-light{--band-bg:#fff;--band-fg:var(--navy)}
.pj-band-light :focus-visible{outline:2px solid var(--navy);outline-offset:2px}
.pj-gallery{border-top:1px solid var(--line)}
.band-grid{display:grid;gap:clamp(2rem,5vw,5rem)}
.band-text h2{font-size:clamp(2rem,4vw,3.25rem);color:var(--band-fg)}
main .band-text p.band-line{margin-top:1rem;font:400 clamp(1.15rem,1.6vw,1.5rem)/1.35 var(--g);color:var(--band-fg)}
.band-media{width:100%;justify-self:end}
.band-media .ph{display:block;width:100%;aspect-ratio:1/1;padding:0;border:0;cursor:zoom-in;border-radius:var(--pj-radius);box-shadow:var(--pj-shadow)}
.gal.gsq{--gallery-tile-max:560px;--gal-gap:1rem;gap:var(--gal-gap);grid-template-columns:repeat(2,minmax(0,1fr));max-width:calc(2*var(--gallery-tile-max) + var(--gal-gap));margin-inline:auto}
.gal.gsq button{aspect-ratio:1/1;border-radius:var(--pj-radius);box-shadow:var(--pj-shadow)}
@media(max-width:599px){.gal.gsq{grid-template-columns:minmax(0,1fr)}}
@media(min-width:861px){
.pj-top{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}
@supports (align-items:last baseline){.pj-top{align-items:last baseline}}
@supports not (align-items:last baseline){.pj-top{align-items:end}.pj-index{position:relative;top:var(--index-baseline-offset)}}
.pj-index{justify-self:end;width:100%;max-width:520px}
.band-grid{grid-template-columns:minmax(0,5fr) minmax(0,7fr);align-items:center}
.band-media{max-width:560px}
}

/* ========================================================================================
   SECTION 22: SHOP PAGE (shop.html)
   Everything here is for the Shop page; the markup and the instructions for sizes,
   stock, price, photos, the email button and a third product are in shop.html. HERO:
   class xs makes the navy hero shorter than the photo heroes (min-height 34 percent of
   the screen height less the header, with less padding); the thin-line drawing is added
   by main.js like on every hero. GRID: shop-grid is one column, and two equal columns
   from 768px. The gap between cards is the variable shop-gap. CARD (class shop-card, the
   article, which also carries the scroll reveal, class rv, switched off under reduced
   motion): a white box with a 1px line border. It is a CSS SUBGRID: every card spans
   three rows of the grid (picture, name row, size row) and uses those same rows, so the
   picture panels, the name rows and the size rows are exactly level and equally tall in
   both cards, whatever the name lengths; spacing between stacked rows of cards is a top
   margin (no row gap, which would split the card's own rows). Browsers without subgrid
   fall back to a plain column inside each card. The hover lift uses the separate
   translate property (so it does not fight the reveal, which uses transform) and a
   shadow, on hover and while a control inside the card has keyboard focus. PICTURE PANEL
   (shop-media): a 4 by 3 box, solid navy, with the thin-line drawing (sm-lines) and the
   white line icon (sm-icon) centred over it; each card holds its product photo as an img laid
   over the whole panel (the notes in shop.html say which file fills which card and how to
   replace it). object-fit cover makes the photo fill the panel completely; both files are
   already exactly 4 by 3, so nothing is cut off. object-position is where the photo is
   anchored inside the panel (the two percentages are across and down, 0% is the left or top
   edge and 100% the right or bottom edge; 50% 50% centres it; change them only if a
   replacement photo has its subject off-centre and a different shape). The img has its own
   solid white background (#ffffff), so no coloured edge can show if the file were a pixel
   short; the navy panel with its thin-line drawing and white icon stays underneath untouched
   as the fallback, and the Shop script in main.js removes the img if it fails to load so that
   panel shows. The photos have no overlay, caption, credit or zoom and are not clickable, and
   they are not lazy-loaded because the cards sit near the top of the page. NAME ROW (shop-name
   holds shop-row): the product name (h2) on the left and the stock badge on the right,
   vertically centred, as one flex row (space between) that never wraps: the name may break
   onto a second line inside its own space (min-width 0), and the badge keeps a fixed space of
   its own, shop-pill-w (10rem, set on shop-grid, a little wider than the widest badge, Out of
   stock), right-aligned inside it, so the width left for the name is the same whichever stock
   state is showing and the rows never change height when a size is chosen. shop-name is a size
   container: when its width is under 470px (the same in both cards because the cards are equal
   width), BOTH cards switch together to the narrow layout: the name on top and the badge under
   it, right-aligned, pushed to the bottom of
   the row so the badges stay level. To change the width at which the badge drops, change
   the 470px. SIZE AND PRICE ROW (shop-size): a flex row that wraps, with align-items flex-end
   so that the bottoms of its two parts are level. On the left, shop-field holds the Size label
   (the site's label style) above the dropdown, left-aligned, at the width of its longest
   option. On the right, directly under the stock badge, shop-pb is the PRICE BLOCK,
   right-aligned (margin-left auto), so its right edge is level with the badge's right edge and
   its bottom level with the dropdown's bottom; if the card is too narrow for both side by side
   (the flex row wraps), the price block drops to its own line under the dropdown and stays on
   the right. The price block keeps its space when it is hidden (visibility hidden, set by the
   script), so a card never changes height. THE PRICE LINE (shop-price): on one line that never
   splits (white-space nowrap), the rufiyaa sign (the svg with class rf), the number (class
   shop-amt) and the words per piece (class shop-unit). The number is Verdana Bold in navy,
   clamp(1.5rem, 2.4vw, 2rem), with lining tabular figures (Verdana's figures are lining, the
   same height as the sign; Georgia's are old-style). The sign is 0.73em high (the height of
   Verdana's digits, em being the number's font size), its width follows its own proportions
   (width auto and the file's aspect ratio, never a fixed width), it sits on the same baseline
   as the digits (inline, vertical-align baseline), it has a gap of 0.2em after it, and its
   fill is currentColor, so it is the same navy as the number. The words per piece are Verdana
   Regular, 0.8rem, in the muted navy tint (the variable navy-l, the same tint as the small
   labels), with a normal space before them in the price font (about 0.4em). THE LABEL
   (shop-gst) under the price: Verdana, 0.75rem, tracked, uppercase through CSS, in the same
   muted tint. The hidden svg that defines the sign has the class rf-defs (no size, out of the
   layout). The dropdown copies the
   Contact page's field style (44px minimum height, 1px border in the same grey-blue,
   square corners, white background, Verdana 0.92rem) with the native arrow switched off
   (appearance none) and a navy chevron drawn as a small inline SVG picture in the
   background (no file). FOCUS RING: no ring on mouse focus; on keyboard focus (focus-visible)
   a single clean 2px navy outline with a 2px offset. Because Chrome treats a dropdown as a
   keyboard control and would show the ring after a mouse click too, the Shop script (main.js)
   adds the class pm to shop-grid when the mouse or a finger was used last and removes it on
   the next key press; while pm is on, the ring and the keyboard-focus lift are switched off
   (the rules with .pm above and below). STOCK BADGE
   (shop-badge): a rounded pill. Out of stock (the default look): the light navy tint
   (the tint variable) with a navy outline, navy text and a dash icon. In stock
   (data-state in, set by the script in main.js from the chosen size's data-stock): solid
   green with white text and a tick icon. The green is the one variable stock-in-bg,
   defined once below and used only for this badge; it is about #1f7a4d, which gives
   white text a contrast of 5.3 to 1 (above the 4.5 to 1 needed). The states differ by
   text and icon as well as colour. EMAIL BUTTON (shop-cta): one button centred under the
   cards, the site's primary button with an envelope icon, at least 48px high. Nothing is shown
   under it: the email address is deliberately not written as text on this page (it lives in
   the button's link), and the space below the button is the section's own bottom padding. THE
   GST NOTE (class shop-note, a p under the cards and above the email button): centred, at most
   60 characters wide (60ch), Verdana 0.85rem in the page's grey (the variable grey) with space
   above it that follows the screen width. The hover lift is switched off under reduced motion
   by the site-wide rule.
   ======================================================================================== */
:root{--stock-in-bg:#1f7a4d}
.hero.xs{min-height:calc(34svh - var(--hh));padding:2rem 0 3rem}
.shop-grid{--shop-gap:clamp(1.5rem,3vw,3rem);--shop-pill-w:10rem;display:grid;grid-template-columns:minmax(0,1fr);column-gap:var(--shop-gap)}
.shop-card{grid-row:span 3;display:grid;grid-template-rows:subgrid;background:#fff;border:1px solid var(--line);transition:opacity .9s,transform .9s,translate .35s ease,box-shadow .35s ease}
.shop-card+.shop-card{margin-top:var(--shop-gap)}
@media(min-width:768px){.shop-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.shop-card+.shop-card{margin-top:0}.shop-card:nth-child(n+3){margin-top:var(--shop-gap)}}
@supports not (grid-template-rows:subgrid){.shop-card{display:flex;flex-direction:column;grid-row:auto}}
.shop-card:hover{translate:0 -4px;box-shadow:0 14px 30px rgba(10,22,48,.14)}
.shop-grid:not(.pm) .shop-card:has(:focus-visible){translate:0 -4px;box-shadow:0 14px 30px rgba(10,22,48,.14)}
.shop-media{position:relative;display:grid;place-items:center;aspect-ratio:4/3;overflow:hidden;background:var(--navy)}
.shop-media .sm-lines{position:absolute;inset:0;width:100%;height:100%}.shop-media .sm-lines path{vector-effect:non-scaling-stroke}
.shop-media .sm-icon{position:relative;width:min(30%,120px);height:auto}
.shop-media img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:50% 50%;background:#fff}
.shop-name{display:flex;container-type:inline-size;padding:clamp(1.2rem,2.2vw,1.8rem) clamp(1.2rem,2.2vw,1.8rem) 0}
.shop-row{flex:1;display:flex;flex-wrap:nowrap;align-items:center;justify-content:space-between;gap:.7rem 1rem;min-height:2.4rem}
.shop-card h2{margin:0;min-width:0;font-size:clamp(1.5rem,2.2vw,1.9rem);line-height:1.15}
.shop-row .shop-status{flex:none;min-width:var(--shop-pill-w);margin:0 0 0 auto;text-align:right}
@container (max-width:470px){.shop-row{flex-direction:column;flex-wrap:nowrap;align-items:stretch;justify-content:space-between}.shop-row .shop-status{align-self:flex-end;min-width:0;margin:0}}
.shop-size{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:.75rem 1rem;padding:1.1rem clamp(1.2rem,2.2vw,1.8rem) clamp(1.2rem,2.2vw,1.8rem)}
.shop-field{display:grid;justify-items:start;gap:.5rem}
.shop-size select{-webkit-appearance:none;appearance:none;min-height:44px;max-width:100%;padding:.6rem 2.6rem .6rem 1rem;border:1px solid #76829b;border-radius:0;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' fill='none' stroke='%230f2043' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 1rem center/12px 12px;font:400 .92rem var(--v);color:var(--ink);cursor:pointer}
.shop-size select:focus{outline:none}
.shop-size select:focus-visible{outline:2px solid var(--navy);outline-offset:2px}
.shop-grid.pm .shop-size select{outline:none}
.shop-status{margin:0}
.shop-badge{display:inline-flex;align-items:center;gap:.5rem;min-height:32px;padding:.3rem .95rem;border:1px solid var(--navy);border-radius:999px;background:var(--tint);color:var(--navy);font:700 .78rem/1.2 var(--v);letter-spacing:.04em;white-space:nowrap}
.shop-badge svg{flex:none;width:14px;height:14px}.shop-badge .i-in{display:none}
.shop-badge[data-state="in"]{background:var(--stock-in-bg);border-color:var(--stock-in-bg);color:#fff}.shop-badge[data-state="in"] .i-out{display:none}.shop-badge[data-state="in"] .i-in{display:block}
.shop-cta{display:flex;flex-direction:column;align-items:center;margin-top:clamp(2.5rem,5vw,3.5rem);text-align:center}
.shop-mail{display:inline-flex;align-items:center;justify-content:center;gap:.8rem;min-height:48px}
.shop-mail svg{flex:none;width:20px;height:20px}
.rf-defs{position:absolute;width:0;height:0;overflow:hidden}
.shop-pb{margin-left:auto;text-align:right}
.shop-size .shop-pb p{margin:0;max-width:none}
.shop-size .shop-price{font:700 clamp(1.5rem,2.4vw,2rem)/1.15 var(--v);color:var(--navy);white-space:nowrap;font-variant-numeric:lining-nums tabular-nums}
.shop-price .rf{display:inline-block;height:.73em;width:auto;aspect-ratio:276.85077/175.59682;margin-right:.2em;vertical-align:baseline;fill:currentColor}
.shop-size .shop-price .shop-unit{font:400 .8rem/1 var(--v);color:var(--navy-l)}
.shop-size .shop-gst{margin-top:.2rem;font:400 .75rem/1.3 var(--v);letter-spacing:.12em;text-transform:uppercase;color:var(--navy-l)}
main p.shop-note{max-width:60ch;margin:clamp(1.5rem,3vw,2.5rem) auto 0;text-align:center;font-size:.85rem;color:var(--grey)}
