/* Ravenor's existing V2 semantics, shared by the homepage and inner pages. */
:root{--bg:#0B0D0C;--on-sage:#15241B;--surface-1:#0E1110;--surface-2:#121517;--surface-3:#16191B;
  --border-1:#1C2220;--border-2:#23282A;--border-3:#2C3331;--sage-bright:#C2DCC6;
  --font-display:'Inter','Noto Sans Armenian',system-ui,sans-serif;
  --font-body:'Inter','Noto Sans Armenian',system-ui,sans-serif;--font-brand:'Orbitron',sans-serif;
  --tr-display:-.035em;--tr-label:.1em;--tr-eyebrow:.12em;--tr-nav:.02em;--tr-brand:.12em;
  --lh-display:1.12;--space-section:clamp(64px,8vw,112px);--card-tx:#a9b0ac;--faint:#89948e}
html{background:var(--bg);scroll-behavior:smooth;scroll-padding-top:100px}
html[lang=ru],html[lang=hy]{--tr-display:-.025em;--tr-label:.025em;--tr-eyebrow:.055em;--tr-nav:0;--lh-display:1.2}
body{font-size:16px;background:var(--bg)}
button,a,input,textarea,select{-webkit-tap-highlight-color:transparent}
button,input,textarea,select{font-family:var(--font-body)}
.rv-wrap{width:100%;max-width:1328px;padding-inline:clamp(22px,4.5vw,64px);margin-inline:auto}
.rv-hdr{padding:18px clamp(22px,4.5vw,64px);min-height:76px;background:rgba(11,13,12,.95);box-shadow:none;border-bottom:1px solid var(--border-2);backdrop-filter:blur(16px)}
.rv-hdr.scrolled{background:rgba(11,13,12,.96);box-shadow:0 8px 26px #0002}
.rv-hdr .brand{font-size:18px;letter-spacing:.1em;gap:11px}
.rv-nav{gap:30px}.rv-nav>a{font-family:var(--font-body);font-size:13px;letter-spacing:0;text-transform:none;font-weight:500;min-height:40px;display:inline-flex;align-items:center}
.rv-nav .nav-quote{border-radius:var(--r-control,2px);padding:11px 17px;font-family:var(--font-body);font-size:13px;letter-spacing:0;background:var(--sage);color:var(--on-sage);border:1px solid var(--sage);min-height:44px}
.globe{min-height:44px;min-width:44px}.menu-btn{width:44px;height:44px}
.rv-mm{background:var(--surface-1);padding:22px;box-shadow:0 24px 40px #0005;border-bottom:1px solid var(--border-3)}
.rv-mm a,.rv-mm>.nav-quote{font-family:var(--font-body);font-size:20px;letter-spacing:0;text-transform:none;min-height:48px}
.rv-mm .mm-langs button{min-height:44px;min-width:54px}
.rv-page-head{padding-top:54px;padding-bottom:48px;background:none;max-width:100%}
.rv-bg::before,.rv-bg::after{display:none}.rv-h1{font-size:clamp(38px,5.8vw,78px);font-weight:500;letter-spacing:-.045em;max-width:1000px;text-transform:none}
.rv-page-head .rv-lead{font-size:clamp(16px,1.7vw,20px);max-width:660px;line-height:1.65;margin-top:22px;color:var(--muted)}
.rv-back{font-size:12px;margin-bottom:30px;letter-spacing:.02em;font-family:var(--font-body);text-transform:none}
.rv-h2{font-size:clamp(26px,3vw,42px);font-weight:500;letter-spacing:-.025em;text-transform:none}
.rv-sect{padding-block:var(--space-section)}.rv-sect-lead{padding-top:32px}
/* alignment is owned by shell.css (.rv-sect-head, baseline); this file sets the gap only - it
   used to also declare align-items:center, which is what pushed the heading 11.6px down its own
   row and gave the sage accent two different distances depending on the section. */
.rv-sect-head{gap:28px}.rv-lead{line-height:1.7;color:var(--muted);font-size:16px;max-width:660px}
.rv-card{border-radius:var(--r-surface,12px);background:var(--surface-1);box-shadow:none}
/* ---------------------------------------------------------------- CTA WEIGHT SYSTEM
   The primary action was a pale mint pill: sage is a low-saturation colour, and at 14px on a
   48px pill it read as a disabled control rather than the main thing on the page. The hue is
   correct — it is the brand mark's own colour, sampled from logo_r.png — so the fix is weight,
   not a new colour.

   A Ravenor primary reads as a MACHINED KEY: a solid face, a light catching its top edge, and
   a shadow that says it stands off the surface. Hover lifts it and the light spreads. Nothing
   here changes the hue, and nothing here is a gradient.

     PRIMARY    solid sage, dark type          one per view, the thing we want pressed
     SECONDARY  dark steel face, sage hairline  the alternative that is still an action
     TEXT LINK  type + dimension mark           navigation inside reading flow
   ------------------------------------------------------------------------------------------ */
.rv-btn{font-family:var(--font-body);font-size:14px;font-weight:600;letter-spacing:.01em;
  text-transform:none;padding:15px var(--ctl-pad-x,24px);min-height:var(--ctl-h,50px);
  border-radius:var(--r-control,2px);gap:12px;
  /* A control's leading belongs to the control. Without this the same button rendered
     50px in a section head and 59px inside a paragraph on /privacy, because it inherited
     the prose line-height of whatever surrounded it. */
  line-height:1.2}
.rv-btn svg{width:var(--ico-md,18px);height:var(--ico-md,18px);flex:none}
.rv-btn-solid{background:var(--sage);color:var(--on-sage);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45),0 12px 30px -18px rgba(171,201,176,.55)}
.rv-btn-solid:hover{background:var(--sage-bright);transform:translateY(-2px);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55),0 18px 38px -18px rgba(171,201,176,.66)}
.rv-btn-solid:active{transform:translateY(0);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3),0 6px 16px -12px rgba(171,201,176,.5)}
/* Secondary: a steel face, not a transparent outline. An outline-only button beside a solid
   one reads as "not really a button"; a face with a hairline reads as the second choice. */
.rv-btn-ghost{background:var(--raised);color:var(--sage);border-color:var(--border-ctl)}
.rv-btn-ghost:hover{background:var(--surface);border-color:var(--ghost-bd);color:var(--sage-bright);
  transform:translateY(-2px);box-shadow:0 12px 26px -18px rgba(0,0,0,.8)}
.rv-btn-ghost:active{transform:translateY(0)}
.rv-idx{font-size:11px;color:var(--muted);letter-spacing:.06em}
/* The bottom pad is written with the safe-area inset folded in, not added below, so a home
   indicator grows the footer's own dark ground instead of producing a separate strip under
   it. 22px is the closing space; on a device with no inset that is all it is. */
.rv-foot{background:var(--surface-1);
  padding-block:64px calc(22px + env(safe-area-inset-bottom,0px));
  border-top:1px solid var(--border-2)}
.rv-foot-grid{gap:56px}.rv-foot-word{font-family:var(--font-brand);font-size:clamp(20px,3vw,34px);letter-spacing:.1em}
.rv-foot-col h2{font-family:var(--font-body);font-size:12px;letter-spacing:.08em;margin-bottom:20px}
.rv-foot-col p,.rv-foot-col>a,.rv-foot-dir{font-size:14px;line-height:1.8}.rv-foot-bot{font-family:var(--font-body);font-size:11px;margin-top:54px;padding-top:24px}
/* Work reads as a collection of photographs with captions, not a stack of dashboard cards. */
/* The column count is NOT restated here. projects.html sets an auto-fill track
   (`repeat(auto-fill,minmax(min(100%,330px),1fr))`) precisely so any number of projects fills its
   rows, and this file — loading after it — was overriding that back to a hard `1fr 1fr` and then
   pushing every even card down by 104px. With four projects and a full-width lead, that put one
   project alone in the left column with half a screen of empty page beside it, and left ragged
   holes between the staggered pair above it. Letting the page's own track do its job gives the
   lead plus a clean row of three at desktop, and it stays correct at five, eight or forty.

   The card also has to stay a flex COLUMN: projects.html pushes each "View project" to the foot
   with margin-top:auto so a two-line title does not leave one card's link riding a line higher
   than its neighbours', and `display:block` here silently disabled that. */
/* stretch, not start: the cards must share a row height for `.pj-go{margin-top:auto}` to line
   every "View project" up. With align-items:start a card whose title wrapped to two lines sat
   taller and its link dropped a line below its neighbours'. */
.pj-grid,.pj-grid.lead{align-items:stretch;gap:clamp(28px,3vw,46px) clamp(18px,2vw,30px)}
.pj-grid .pj-card,.pj-grid.lead .pj-card{grid-column:auto;background:transparent;border:0;border-radius:0;transform:none;box-shadow:none;display:flex;flex-direction:column}
.pj-grid .pj-card .rv-frame,.pj-grid.lead .pj-card .rv-frame{position:relative;aspect-ratio:4/3;height:auto;min-height:0;border-radius:10px;overflow:hidden}
/* `display:block` here also defeated the foot-aligned CTA: projects.html relies on .pj-body being
   a flex column so `.pj-go{margin-top:auto}` can push every "View project" to the same baseline
   regardless of whether a title wrapped to two lines. */
.pj-grid .pj-card .rv-frame::after{display:none}.pj-grid .pj-card .pj-body,.pj-grid.lead .pj-card .pj-body{position:static;background:transparent;padding:22px 0 0;display:flex;flex-direction:column;flex:1 1 auto}
.pj-grid .pj-card h3,.pj-grid.lead .pj-card h3{font-size:clamp(20px,2vw,28px);font-family:var(--font-body);font-weight:500;letter-spacing:-.025em;line-height:1.25;max-width:95%}
.pj-grid .pj-top{margin-bottom:12px}
/* margin-top stays `auto` so the link is pushed to the foot of an equal-height card; a fixed
   17px here was silently overriding projects.html's foot alignment, which is why a card with a
   two-line title dropped its "View project" a line below its neighbours'. The air it wanted is
   padding-top instead. */
.pj-grid .pj-go{position:static;margin-top:auto;padding-top:17px;display:inline-flex;font-size:13px;font-weight:500;opacity:1;transform:none;color:var(--sage)}
.pj-grid .rv-chips{margin-top:12px}.rv-spec .cell{padding:14px 22px 14px 0}
/* The spec strip summarises the grid directly above it, so it belongs to that grid rather than
   floating between two sections - 56px had it reading as its own orphaned band. */
.pj-spec{margin-top:clamp(28px,3vw,40px)}
/* Where two full sections meet, their padding stacked: 112px bottom + 112px top put 224px of
   nothing between the last line of one section and the first of the next, which is the "giant
   empty space" the owner kept hitting on the inner pages. A section boundary needs ONE measure of
   air, not two. */
.rv-sect + .rv-sect{padding-top:clamp(40px,4.6vw,66px)}
/* ...and the same on the other side of the boundary, so the pair is one measure of air rather
   than one-and-a-half. `:has()` degrades safely - a browser without it simply keeps the larger
   spacing this rule was written to reduce, which is the behaviour that shipped before. */
.rv-sect:has(+ .rv-sect){padding-bottom:clamp(40px,4.6vw,66px)}
/* ------------------------------------------------------------------ SERVICES AS BANDS
   Services are an editorial index; drawings remain honest when owner photography is absent.

   The previous rule put the photograph on its own full-rail row above a four-column text strip,
   and it did not work: `aspect-ratio:16/10` capped by `max-height:340px` cannot satisfy both, so
   the browser solved for height and shrank the picture to 544px wide — leaving roughly 650px of
   empty page beside every one of the eight services, which is most of what made this page read
   as unfinished. The text strip underneath then spread four columns across the full rail, so the
   summary and its link ended up far apart with more emptiness between them.

   A service is now a BAND: the photograph on the left at a declared ratio, the whole description
   beside it, vertically centred. The picture fills the height it is given, the copy has a sane
   measure instead of a full-rail line, and the row is about 320px instead of 700px — so the page
   is also half as long.
   ------------------------------------------------------------------------------------------ */
.sv-grid{display:flex;flex-direction:column;gap:0;border-top:1px solid var(--border-2)}
/* flex-direction is stated, not assumed: services.html's own <style> sets the card to a COLUMN
   for its card-grid layout, and this file loads after it, so leaving the direction unset left the
   band stacked vertically with a full-rail photograph on top of centred copy. */
.sv-grid .sv-card{display:flex;flex-direction:row;align-items:center;gap:clamp(24px,3.4vw,56px);
  padding:clamp(26px,3vw,40px) 0;border:0;border-bottom:1px solid var(--border-2);
  border-radius:0;background:transparent;box-shadow:none;transform:none;min-height:150px}
.sv-grid .sv-card:hover{background:linear-gradient(90deg,transparent,rgba(171,201,176,.035),transparent)}
.sv-grid .sv-body{display:flex;flex-direction:column;align-items:flex-start;gap:14px;
  flex:1 1 auto;min-width:0}
.sv-grid .sv-idxrow{margin:0;display:flex;gap:12px;align-items:center}
.sv-grid .sv-idxrow .rv-ico{width:var(--ico-2xl,38px);height:var(--ico-2xl,38px);margin:0;color:var(--sage)}
.sv-grid .sv-card h3{font-size:clamp(22px,2.7vw,34px);font-weight:500;letter-spacing:-.03em;margin:0;text-transform:none}
.sv-grid .sv-card p{font-size:15px;line-height:1.7;margin:0;color:var(--muted);max-width:54ch}
.sv-grid .sv-go{margin:0;font-size:12px;letter-spacing:0}
/* The three bullets, set as a spec list: a sage datum tick, a hairline measure, and the fact.
   Two columns from 1080 up so they occupy the width the band actually has rather than running
   as one narrow stack beside a wide photograph. */
.sv-grid .sv-bul{list-style:none;margin:2px 0 0;padding:0;display:grid;gap:9px 26px;width:100%}
@media(min-width:1080px){ .sv-grid .sv-bul{grid-template-columns:repeat(2,minmax(0,1fr))} }
.sv-grid .sv-bul li{position:relative;padding-left:18px;font-size:13.2px;line-height:1.55;
  color:var(--card-tx)}
.sv-grid .sv-bul li::before{content:'';position:absolute;left:0;top:.62em;width:8px;height:1px;
  background:var(--sage);opacity:.8}
.sv-grid .sv-cover{flex:0 0 clamp(240px,38%,440px);aspect-ratio:4/3;max-height:none;height:auto;
  margin:0;border-radius:var(--r-surface,12px);overflow:hidden;align-self:center}
.sv-grid .sv-cover img,.sv-grid .sv-cover video{width:100%;height:100%;object-fit:cover}
/* A service with no photograph must not leave a hole where the picture would be: the copy simply
   takes the rail, which is what an index entry without an illustration should do. */
.sv-grid .sv-card:not(.has-cover) .sv-body{max-width:none}
@media(max-width:860px){
  .sv-grid .sv-card{flex-direction:column;align-items:stretch;gap:20px}
  .sv-grid .sv-cover{flex:0 0 auto;width:100%;aspect-ratio:16/9}
}
.pr-step{padding-block:36px}.pr-head h2{font-family:var(--font-body);font-size:clamp(21px,2.5vw,30px);letter-spacing:-.025em;font-weight:500}
.pr-txt p{font-size:16px;line-height:1.75}.pr-canon{font-size:11px;letter-spacing:.055em}.pr-num{box-shadow:none!important}
/* The promises are a spec block now, not cards - `.pr-prom .rv-card` has nothing left to style,
   and this file loads AFTER process.html's own <style>, so its 15px paragraph was quietly
   overriding the 14px the block is set at on the homepage. Same content, same grammar, so the
   same type: measured at 14px/1.75 against `.promise-list` in home.css. */
.pr-prom p{font-size:14px;line-height:1.75}.pr-prom h3{letter-spacing:.01em}
.ct-fld label{font-size:13px;letter-spacing:0;text-transform:none}.ct-fld input,.ct-fld textarea{font-size:16px;min-height:48px}.ct-fld .rv-seg label{display:flex;min-height:44px}
.rv-seg label{min-height:44px}.rv-input{font-size:16px;min-height:48px}.rv-err{font-size:13px}
/* Quote: one quiet sheet, readable controls and a persistent, named mobile entry point. */
/* The drawer was a 430px column at every desktop size, which is why it read as cramped: an
   enquiry with a phone field, a currency, a range and a message needs room. It now scales
   with the viewport and stops before it becomes a wall. */
/* 40vw put the panel at 576px on a 1440 screen, which is where its density complaint came
   from: two-column field pairs and five budget chips were being squeezed into a column narrower
   than the reading measure of the page behind it. The extra width is spent on BREATHING, not on
   stretching inputs - the chips get one row instead of two and the paired fields stop touching. */
.rv-quote{width:min(clamp(440px,46vw,720px),96vw);background:var(--surface-1);border-left:1px solid var(--border-3);box-shadow:-30px 0 90px #0005}
.rv-quote-field{display:none}.rv-quote-head{padding:20px 24px;background:var(--surface-1)}
.rv-quote-head h2{font-family:var(--font-body);font-size:25px;letter-spacing:-.03em;line-height:1.2;font-weight:500}
.rv-quote-head::after{display:none}.rv-quote-body{padding:22px 24px}.rv-quote-sub{font-size:15px;line-height:1.7;margin-bottom:20px}
.rv-quote .fld>label{font-family:var(--font-body);font-size:13px;letter-spacing:0;text-transform:none}
.rv-quote input,.rv-quote textarea{font-size:16px}.rv-quote .rv-x{width:44px;height:44px;border-color:var(--border-3)}
.rv-quote-foot{padding:16px 24px 20px;background:var(--surface-1);border-top:1px solid var(--border-2)}
.rv-quote-note{font-size:11px;line-height:1.65}.rv-quote-cap{display:none}.rv-disc summary{padding:16px 0;font-family:var(--font-body)}
/* The closed quote trigger is the slim tab welded to the right edge, as it ships in
   quote.css and as production presents it. The overrides that used to live here turned it
   into a bottom-right pill, which duplicated the header's quote button and sat on top of
   the page content. The pill treatment now applies only below 760px, in assistant.css,
   where the header button is inside the burger and an edge tab would be awkward. */
.rv-quote-handle svg{width:var(--ico-sm,16px)}
body.rv-locked .rv-quote-handle{visibility:hidden}.q-section-title{font-size:11px;letter-spacing:.06em;color:var(--muted);margin:22px 0 14px;text-transform:uppercase}
.q-progress{display:flex;gap:10px;align-items:center;margin-bottom:20px;font-size:12px;color:var(--muted);line-height:1.5}.q-progress::before{content:'';width:6px;height:6px;border:1px solid var(--muted);border-radius:50%;flex:none}.q-progress.ready::before{background:var(--sage);border-color:var(--sage)}
.q-clear{display:block;margin:14px auto 0;font-size:12px;color:var(--muted);text-decoration:underline;min-height:36px}.q-clear:hover{color:var(--text)}
@media(max-width:1100px){.rv-nav{gap:18px}.rv-hdr .brand{font-size:16px}.sv-grid .sv-card{grid-template-columns:70px 1fr 1fr}.sv-grid .sv-go{grid-column:2}}
@media(max-width:760px){.rv-quote{width:100%}}
@media(max-width:900px){.rv-nav>a{display:none}.rv-hdr{padding-block:14px;min-height:70px}.rv-nav{margin-left:auto;margin-right:16px}.menu-btn{display:flex}.rv-page-head{padding-top:36px}}
@media(max-width:600px){.rv-hdr .brand{font-size:14px;gap:var(--brand-mark-gap,.187em)}.rv-nav{margin-right:4px}.rv-nav .nav-quote{display:none}.rv-wrap{padding-inline:22px}.rv-page-head{padding-block:30px 36px}.rv-h1{font-size:40px;letter-spacing:-.04em}.rv-back{margin-bottom:24px}.rv-page-head .rv-lead{font-size:16px;margin-top:18px}.rv-sect-head{align-items:flex-start}.pj-grid,.pj-grid.lead{grid-template-columns:1fr;gap:36px}.pj-grid .pj-card h3{font-size:24px}.sv-grid .sv-card{gap:18px;padding-block:28px}.sv-grid .sv-idxrow .rv-ico{width:30px;height:30px}.sv-grid .sv-card h3{font-size:25px}.rv-foot{padding-top:44px}.rv-foot-grid{gap:36px}.rv-foot-bot{gap:14px;margin-top:32px}.rv-quote-head{padding:18px 22px}.rv-quote-head h2{font-size:22px}.rv-quote-body{padding:24px 22px}.rv-quote-foot{padding:16px 22px max(20px,env(safe-area-inset-bottom))}.pr-txt p{font-size:15px}}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}.rv-rise{opacity:1;transform:none}}
.rv-nav .nav-quote{color:#15241B!important}
.assistant-trigger{bottom:88px}
.q-section-title small{display:block;margin-top:8px;font-size:10px;text-transform:none;color:var(--muted)}.q-clear{background:none;border:0;cursor:pointer;margin:0 0 0 auto;flex:none;padding:4px}.q-progress>span{flex:1}.rv-quote-done h3{font-family:var(--font-body);letter-spacing:-.025em}
.sv-grid .sv-card h3{font-family:var(--font-body);font-size:clamp(22px,2.7vw,34px);font-weight:500;letter-spacing:-.03em;margin:0;text-transform:none}
body .assistant-trigger{bottom:88px}
.q-order-reference{margin:22px 0;padding:18px 22px;border:1px solid var(--sage);border-radius:var(--r-surface,12px);display:grid;gap:8px;color:var(--text-hi);overflow-wrap:anywhere}.q-order-reference strong{font:15px var(--font-mono)}
/* The subscribe block is a bordered CTA surface, which is the `--r-surface` family, and it was
   sitting at a hard 0. Named by the owner directly. */
.rv-subscription{border-radius:var(--r-surface,12px);}
.rv-sub-row{border-radius:var(--r-control,6px)}
/* NOT the cards. `.pj-card` and `.sv-card` are deliberately transparent with no border and no
   box - the rounded thing there is `.rv-frame`, the image itself, already at 10px. Rounding a
   box that is not drawn would have changed nothing visible and hidden that fact behind a rule. */
.rv-subscription{display:grid;grid-template-columns:1fr 1fr;gap:48px;border-top:1px solid var(--border-2);margin-top:40px;padding-top:36px}.rv-subscription h2{font:400 clamp(24px,3vw,36px)/1.2 var(--font-body);letter-spacing:-.025em;max-width:340px}.rv-sub-form{position:relative}.rv-sub-form>label{display:block;font-size:12px;color:var(--muted);margin-bottom:10px}.rv-sub-row{display:flex;gap:10px}.rv-sub-row input{min-width:0;flex:1;border:1px solid var(--border-field);background:var(--surface-1);border-radius:var(--r-control,2px);padding:12px 14px;color:var(--text-hi);font:16px var(--font-body)}.rv-sub-form .rv-sub-consent{display:flex;align-items:flex-start;gap:12px;font-size:12px;line-height:1.6;margin:16px 0 10px}.rv-sub-consent input{flex:none;margin-top:3px;width:16px;height:16px;accent-color:var(--sage)}.rv-sub-privacy{font-size:11px;color:var(--sage)}.rv-sub-status{font-size:12px;line-height:1.6;margin-top:12px;min-height:20px}.rv-sub-hp{position:absolute;left:-9999px;opacity:0;width:1px;height:1px}.rv-subscription input:focus-visible{outline:2px solid var(--sage);outline-offset:3px}
@media(max-width:600px){body .assistant-trigger{bottom:18px}.sv-grid .sv-card h3{font-size:25px}.rv-subscription{grid-template-columns:1fr;gap:24px}.rv-sub-row{flex-wrap:wrap}.rv-sub-row button{min-height:44px}}

.rv-breadcrumb{display:flex;gap:12px;align-items:baseline;flex-wrap:wrap;color:var(--muted);font-size:11px;line-height:1.7;margin-bottom:26px}.rv-breadcrumb a{color:var(--sage);text-decoration:none}.rv-breadcrumb [aria-current]{overflow-wrap:anywhere}

.ct-map{background:radial-gradient(ellipse at 40% 20%,#23362a,#0e1510)}.ct-map iframe[hidden]{display:none}.ct-map-fb{z-index:2!important;background:transparent!important}.ct-map-fb /* same control family as every other action */
.ct-map-load{margin-top:14px}.ct-map-fb.map-loaded{inset:auto 12px 12px;padding:10px 16px;gap:4px;background:#0b0d0ce8!important;border:1px solid var(--border-2);border-radius:8px}.ct-map-fb.map-loaded .pin,.ct-map-fb.map-loaded #ctMapAddr{display:none}


/* ------------------------------------------------------------------ footer close-out
   The newsletter heading was inheriting `.rv-foot h2`'s uppercase while overriding only its size,
   so a 36px all-caps Armenian sentence was being packed into a 340px column and broke three ways
   with one word stranded on the last line. It is a footer heading, not a section title: it sits
   above the footer's label scale and well below the page's, and it reads in sentence case. */
.rv-subscription h2{text-transform:none;font-size:clamp(19px,1.8vw,24px);line-height:1.3;
  letter-spacing:-.01em;max-width:26ch;color:var(--text-hi)}
/* Identity on the left, the legal links grouped on the right, so the copyright line is read as
   the company's own statement rather than as one more link in a row. */
.rv-foot-bot .rv-foot-legal-links{display:flex;gap:22px;flex-wrap:wrap}
.rv-foot-bot .rv-foot-legal-links a{color:var(--faint);transition:color var(--t-fast)}
.rv-foot-bot .rv-foot-legal-links a:hover{color:var(--sage)}
/* column-REVERSE, not column. The DOM is identity-first, which is the order the desktop row
   uses and the order a screen reader should hear; stacking it plainly put the legal links
   under the copyright, so the last thing on a phone was "Your information" and the identity
   line no longer closed the page. Reversing the visual axis fixes that without touching the
   markup or the reading order. */
@media(max-width:520px){.rv-foot-bot{flex-direction:column-reverse;gap:12px}}

/* ==============================================================================================
   RAVENOR INTERACTION SYSTEM
   One vocabulary for every action on the site, so a primary CTA, a quiet text link and a card
   affordance are recognisably the same family rather than five inherited treatments.

     PRIMARY   .rv-btn.rv-btn-solid   the one action a screen most wants
     SECONDARY .rv-btn                equal weight, lower emphasis
     TEXT      .text-link             inline, carries the drawn mark
     CARD      .home-project / .service-line   the whole surface is the target
     UTILITY   .reviews-write, small controls

   Every hover response is gated behind `@media (hover:hover)`, because on touch a :hover rule
   sticks after the tap and leaves a control looking permanently pressed. Focus is styled first,
   not as an afterthought, and every transition is dropped under reduced motion.
   ============================================================================================== */

.rv-btn,.text-link,.reviews-write{
  position:relative;transition:color var(--t-ctl) var(--ease),background-color var(--t-ctl) var(--ease),
  border-color var(--t-ctl) var(--ease),box-shadow var(--t-ctl) var(--ease),transform var(--t-ctl) var(--ease)}

/* --- PRIMARY: a light sweep passes once, the brand green lifts underneath --- */
.rv-btn-solid{overflow:hidden;isolation:isolate}
.rv-btn-solid::after{content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(105deg,transparent 30%,rgba(255,255,255,.30) 50%,transparent 70%);
  transform:translateX(-120%);transition:transform .62s var(--ease)}
@media(hover:hover){
  .rv-btn-solid:hover::after,.rv-btn-solid:focus-visible::after{transform:translateX(120%)}
  .rv-btn-solid:hover{transform:translateY(-1px);
    box-shadow:0 10px 26px -14px rgba(171,201,176,.85),0 0 0 1px rgba(171,201,176,.30)}
}
.rv-btn-solid:active{transform:translateY(0);box-shadow:none}

/* --- SECONDARY: the border lights, the surface warms a little --- */
@media(hover:hover){
  .rv-btn:not(.rv-btn-solid):hover{color:var(--sage);border-color:var(--sage);
    background:rgba(171,201,176,.06);transform:translateY(-1px)}
}
.rv-btn:not(.rv-btn-solid):active{transform:translateY(0);background:rgba(171,201,176,.10)}

/* --- TEXT: the dimension mark IS the line reveal --- */
/* This control used to carry a SECOND drawn line: a `.text-link::before` underline that swept
   in on hover while the mark also travelled. Two line-reveals inside one control is one
   accessory too many, and the rule had two real defects behind it — `.text-link` was never
   position:relative, so the absolutely-positioned underline anchored to whatever ancestor
   happened to be positioned and floated free of its own label; and the reduced-motion block
   pinned it to scaleX(1), so every visitor with reduced motion saw a permanent stray rule
   under every link on the site rather than a hover affordance.
   The mark's own rule now does this job, and hover still changes colour, so the affordance is
   intact for pointer, keyboard and reduced-motion visitors alike. */
.text-link{position:relative;display:inline-flex;align-items:center;gap:0;padding-block:4px}
@media(hover:hover){ .text-link:hover{color:var(--sage)} }

/* --- UTILITY --- */
.reviews-write{border-bottom:1px solid var(--border-ctl);padding-bottom:2px}
@media(hover:hover){.reviews-write:hover{color:var(--sage);border-bottom-color:var(--sage)}}
/* The TEXT roles are controls too, and the coarse-pointer floor was reaching `.rv-btn` and the
   skip link only. `.reviews-write` measured 36px - a real miss on a phone - and
   `.rv-sub-manage` was outside the documented system altogether: no shared transition, no
   shared focus ring, no pressed state. All three now sit in the same family as everything
   else. */
.rv-sub-manage{position:relative;transition:color var(--t-ctl) var(--ease)}
@media(hover:hover){.rv-sub-manage:hover{color:var(--sage)}}
.rv-sub-manage:focus-visible{outline:2px solid var(--sage);outline-offset:3px;border-radius:6px}
/* A press must be felt on touch, where there is no hover to precede it. */
.text-link:active,.reviews-write:active,.rv-sub-manage:active{opacity:.7}
@media (pointer:coarse){
  .text-link,.reviews-write,.rv-sub-manage{min-height:var(--ctl-h-min,44px);
    display:inline-flex;align-items:center}
}

/* --- focus is first-class everywhere --- */
.rv-btn:focus-visible,.text-link:focus-visible,.reviews-write:focus-visible,
.home-project:focus-visible,.service-line:focus-visible{
  outline:2px solid var(--sage);outline-offset:3px;border-radius:6px}

/* --- disabled reads as unavailable, not as broken --- */
.rv-btn[disabled],.rv-btn[aria-disabled=true]{opacity:.45;pointer-events:none;box-shadow:none;transform:none}

@media(prefers-reduced-motion:reduce){
  .rv-btn,.text-link,.reviews-write,.link-mark,.rv-btn-solid::after{transition:none}
  .rv-btn-solid:hover{transform:none}
}

/* ---------------------------------------------------- floating controls vs page content
   The fixed quote trigger and Ask Ravenor sit above the page, so on a phone they were landing on
   service rows, project cards and the footer address. Two corrections, no functionality removed:

   1. the last two sections reserve room for them, so nothing is permanently covered;
   2. once the conversion section or the footer is on screen the floating pair stands down - those
      areas carry their own "discuss your project" and full contact details, so a floating shortcut
      to the same thing is duplicate clutter exactly where the owner asked for less of it. */
@media(max-width:760px){
  .home-contact{padding-bottom:calc(52px + 76px)}
  /* The footer's own 86px reservation is GONE. Correction 2 above already covers this case:
     the observer watches `.rv-foot`, so the floating pair has stood down before any part of the
     footer is on screen, and the room reserved for them was room nothing could ever occupy. What
     it did instead was leave an 86px band of empty ground under the copyright - the dead space
     the owner pointed at, and the reason the page did not appear to end where it ends.
     `.home-contact` keeps its reservation: that section is tall, a visitor can sit inside it with
     the footer far below, and there the controls are genuinely still up. */
}
/* Standing down must not also RE-ANCHOR the tab. The tab is centred with translateY(-50%),
   so a bare translateY(12px) here replaced that centring outright: for the 0.32s of the fade the
   control travelled half the viewport upwards on its way out, and half a viewport back down on
   its way in. Invisible at opacity 0 only at the very end of the curve - the first third of the
   fade is still clearly on screen. The step is composed with the centring now, so the tab leaves
   and returns from where it actually lives. The assistant trigger is bottom-anchored and has no
   centring to preserve, so it keeps the plain step. */
body.rv-cta-rest .rv-quote-handle{
  visibility:hidden;  opacity:0;pointer-events:none;transform:translateY(calc(-50% + 12px))}
body.rv-cta-rest .assistant-trigger{
  visibility:hidden;  opacity:0;pointer-events:none;transform:translateY(12px)}
.rv-quote-handle,.assistant-trigger{
  transition:opacity .32s var(--ease),transform .32s var(--ease)}
@media(prefers-reduced-motion:reduce){
  .rv-quote-handle,.assistant-trigger{transition:none}
}

/* --------------------------------------------------- mobile tap targets that were under size
   Measured on a 390px viewport: a menu row whose target was only as wide as its text, a 16px
   consent checkbox, and a 26px-tall legal link. The visual size of the checkbox is kept - only
   its hit area grows, which is what the guideline is actually about. */
.rv-mm a,.rv-mm .nav-quote{display:flex;align-items:center;width:100%;min-height:48px}
.rv-sub-consent{position:relative;padding-block:8px;min-height:44px}
.rv-sub-consent input[type=checkbox]{width:18px;height:18px}
.rv-sub-consent input[type=checkbox]::before{content:'';position:absolute;left:-10px;top:0;
  width:44px;height:100%}
.rv-foot-bot .rv-foot-legal-links a{display:inline-flex;align-items:center;min-height:44px}
/* Breadcrumb links measured 19px tall on a phone - under the 24px WCAG 2.5.8 floor, and the
   inline-text exception does not cover a breadcrumb row, which is navigation rather than prose.
   The fix is hit area, not size: padding grows the target and an equal negative margin gives the
   space straight back, so the row's baseline alignment, its 12px gaps and its 26px bottom margin
   are all exactly where they were. Coarse pointers only - a mouse does not need it and the
   desktop rhythm stays untouched.
   Verified against qa/site_matrix_audit.py, which measures the rendered rect rather than the
   declared font-size; the 18px consent checkbox it also flags is a FALSE POSITIVE, because that
   control already carries a 44px ::before hit area a few lines above. */
@media(pointer:coarse){
  .rv-breadcrumb a,.rv-crumb a{display:inline-block;padding-block:7px;margin-block:-7px}
  /* Two standalone links sat just under the 44px comfort target at 40-41px. */
  .reviews-write,.rv-map-link{min-height:44px;display:inline-flex;align-items:center}
}
/* Footer column links sit in a vertical list, so the row is the natural target - a link only as
   wide as the word "Կապ" is a 36px target on a phone. */
.rv-foot-col a{width:100%}

/* ==============================================================================================
   PROJECT GALLERY (lightbox)
   Full-bleed dark stage, one image, a real header that says which project and where you are in
   it, and a separate action to the project page. Not a modal with a giant X.
   ============================================================================================== */
body.rv-gal-lock{overflow:hidden}
.rv-gal{position:fixed;inset:0;z-index:200;display:flex;opacity:0;transition:opacity .22s var(--ease)}
.rv-gal.on{opacity:1}
.rv-gal-scrim{position:absolute;inset:0;background:rgba(5,7,6,.93);backdrop-filter:blur(8px)}
.rv-gal-shell{position:relative;display:flex;flex-direction:column;width:100%;height:100%;
  padding:clamp(14px,2vw,26px)}
.rv-gal-head{display:flex;align-items:center;justify-content:space-between;gap:20px;flex:none;
  padding-bottom:clamp(10px,1.4vw,18px)}
.rv-gal-id{display:flex;align-items:baseline;gap:16px;min-width:0}
.rv-gal-title{font-family:var(--font-body);font-size:clamp(15px,1.6vw,21px);color:var(--text-hi);
  letter-spacing:-.02em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rv-gal-count{font:11px var(--font-mono);letter-spacing:.12em;color:var(--muted);flex:none}
.rv-gal-count b{color:var(--sage);font-weight:400}
.rv-gal-count i{opacity:.5;font-style:normal;margin:0 3px}
.rv-gal-acts{display:flex;align-items:center;gap:clamp(14px,2vw,26px);flex:none}
.rv-gal-open{font-size:13px}
/* `.text-link` sets display:inline-flex, which outranks the [hidden] attribute - so a service
   gallery, which has no "View project" to offer, would still have shown one. */
.rv-gal-open[hidden]{display:none}
.rv-gal-x{width:44px;height:44px;flex:none;border:1px solid var(--border-3);border-radius:50%;
  background:transparent;color:var(--text);cursor:pointer;position:relative;
  transition:border-color var(--t-ctl),color var(--t-ctl),transform var(--t-ctl)}
.rv-gal-x::before,.rv-gal-x::after{content:'';position:absolute;left:13px;right:13px;top:21px;
  height:1.5px;background:currentColor}
.rv-gal-x::before{transform:rotate(45deg)}
.rv-gal-x::after{transform:rotate(-45deg)}
@media(hover:hover){.rv-gal-x:hover{border-color:var(--sage);color:var(--sage);transform:rotate(90deg)}}
.rv-gal-x:focus-visible{outline:2px solid var(--sage);outline-offset:3px}

.rv-gal-stage{flex:1 1 auto;min-height:0;display:flex;align-items:center;justify-content:center}
.rv-gal-fig{margin:0;display:flex;flex-direction:column;align-items:center;gap:14px;
  max-width:100%;max-height:100%}
.rv-gal-fig img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  border-radius:10px;box-shadow:0 40px 120px -50px rgba(0,0,0,.9)}
.rv-gal-fig figcaption{font-size:13px;line-height:1.6;color:var(--muted);text-align:center;
  max-width:70ch}

/* ------------------------------------------------------- GALLERY NAV, in the site's grammar
   These were 52px circles with a bare chevron - the default "image carousel" control, which
   belongs to no brand and was the last interactive object still outside Ravenor's vocabulary.
   They carry the DIMENSION MARK now, the same rule-plus-terminator used by every link on the
   site, on a square hairline plate rather than a circle: the product has no other circular
   surfaces, and a machined plate is the right object for a workshop.

   Usability is not traded for it - the plate is larger than the circle was (56px), the contrast
   is higher, and the hit area is unchanged in position. */
.rv-gal-nav{position:absolute;top:50%;transform:translateY(-50%);width:56px;height:56px;
  border:1px solid var(--border-3);border-radius:11px;background:rgba(10,13,11,.55);
  backdrop-filter:blur(8px);color:var(--text-hi);cursor:pointer;
  transition:border-color var(--t-ctl) var(--ease),background var(--t-ctl) var(--ease),
             color var(--t-ctl) var(--ease)}
/* the measurement rule */
.rv-gal-nav::before{content:'';position:absolute;top:50%;left:50%;width:24px;height:1px;
  margin-left:-12px;background:currentColor;
  transform:translateY(-50%) scaleX(.55);
  transition:transform var(--t-move) var(--ease-line)}
/* the terminator */
.rv-gal-nav::after{content:'';position:absolute;top:50%;left:50%;width:6px;height:6px;
  border-top:1.5px solid currentColor;border-right:1.5px solid currentColor;
  transition:transform var(--t-move) var(--ease-line)}
.rv-gal-nav.next{right:clamp(10px,2vw,26px)}
.rv-gal-nav.next::before{transform-origin:left center}
.rv-gal-nav.next::after{transform:translate(2px,-50%) rotate(45deg)}
.rv-gal-nav.prev{left:clamp(10px,2vw,26px)}
.rv-gal-nav.prev::before{transform-origin:right center}
.rv-gal-nav.prev::after{transform:translate(-8px,-50%) rotate(-135deg)}
@media(hover:hover){
  .rv-gal-nav:hover{border-color:var(--sage);color:var(--sage);background:rgba(10,13,11,.75)}
  /* the measurement is taken: the rule runs out and the terminator travels with it */
  .rv-gal-nav:hover::before{transform:translateY(-50%) scaleX(1)}
  .rv-gal-nav.next:hover::after{transform:translate(8px,-50%) rotate(45deg)}
  .rv-gal-nav.prev:hover::after{transform:translate(-14px,-50%) rotate(-135deg)}
}
.rv-gal-nav:focus-visible{outline:2px solid var(--sage);outline-offset:3px}
@media(prefers-reduced-motion:reduce){
  .rv-gal-nav::before,.rv-gal-nav::after{transition:none}
}

.rv-gal-dots{display:flex;justify-content:center;gap:7px;flex:none;padding-top:14px}
.rv-gal-dots i{width:6px;height:6px;border-radius:50%;background:var(--border-ctl);
  transition:background .3s var(--ease),width .3s var(--ease)}
.rv-gal-dots i.on{background:var(--sage);width:18px;border-radius:99px}

@media(max-width:760px){
  .rv-gal-nav{display:none}          /* swipe is the gesture on touch; dots show position */
  .rv-gal-title{white-space:normal;font-size:15px}
  .rv-gal-head{align-items:flex-start;flex-direction:column;gap:10px}
  .rv-gal-acts{width:100%;justify-content:space-between}
}
@media(prefers-reduced-motion:reduce){
  .rv-gal,.rv-gal-x,.rv-gal-nav,.rv-gal-dots i{transition:none}
  .rv-gal-x:hover{transform:none}
}

/* ============================================================ QUOTE DRAWER — CONSULTATION
   The drawer is no longer a wizard (see buildPanel in quote.js): everything is in one calm
   scroll. These rules give that scroll a shape, and remove the last of the browser's own chrome
   from a surface that is supposed to feel built rather than assembled.
   ========================================================================================= */

/* --- sections read as two chapters, not one long run of labels --- */
.rv-quote .q-block{padding-block:clamp(20px,2.4vw,28px)}
.rv-quote .q-block + .q-block{border-top:1px solid var(--border-2)}
.rv-quote .q-block-lead{padding-top:0;padding-bottom:4px}
.rv-quote .q-block > .q-section-title{margin-top:0;padding-top:0;border-top:0}
.rv-quote .q-block > .fld:last-child{margin-bottom:0}
/* "Optional" is a property of the section, so it sits on the heading's line rather than being
   pushed to its own row underneath it by the mobile rule. */
.rv-quote .q-section-title small{display:inline;margin:0 0 0 auto;font-size:10.5px;
  letter-spacing:.06em;color:var(--faint);text-transform:none}

/* the currency caret lives with the other select rules, in quote.css */

/* --- the disclosures state their question clearly --- */
.rv-quote .rv-disc summary .dk{color:var(--text-rev)}
.rv-quote .rv-disc summary{min-height:48px}
.rv-quote .rv-disc summary svg{color:var(--sage)}
/* the budget block held a bordered card inside a bordered card; one frame is enough */
.rv-quote .rv-budget-block{border-color:var(--border-2);background:rgba(255,255,255,.016)}
.rv-quote .rv-budget-block > .rv-disc{border:0;background:transparent;
  border-top:1px solid var(--div);border-radius:0}
.rv-quote .rv-budget-block > .rv-disc summary{padding-inline:0}
.rv-quote .rv-budget-block > .rv-disc .rv-disc-body{padding-inline:0}
.rv-quote .rv-budget-block > .rv-disc[open] summary{border-bottom:0}

/* --- the action bar --- */
/* The readiness line led with a hollow 6px ring that read as a bullet nobody had filled in.
   It is a STATE, so it is drawn as one: a dark tick that lights sage the moment the form has
   something to send. */
.rv-quote .q-progress{gap:12px;font-size:12.5px;color:var(--muted)}
.rv-quote .q-progress::before{width:7px;height:7px;border-radius:50%;border:0;
  background:var(--border-ctl);transition:background var(--t-ctl) var(--ease),
  box-shadow var(--t-ctl) var(--ease)}
.rv-quote[data-ready="1"] .q-progress::before{background:var(--sage);
  box-shadow:0 0 0 3px rgba(171,201,176,.18)}
.rv-quote[data-ready="1"] .q-progress{color:var(--text-rev)}
/* The privacy reassurance was set in monospace with wide tracking, which reads as a console
   message rather than as the product speaking. It is the last thing a visitor reads before
   sending their details, so it is set in the body face like everything else they have read. */
.rv-quote .rv-quote-note{font-family:var(--font-body);letter-spacing:.01em;font-size:11.5px;
  line-height:1.6;color:var(--faint);max-width:46ch;margin-inline:auto}
.rv-quote #rvQSend{min-height:54px;font-size:14.5px}

/* ------------------------------------------------ the last native control on the site
   The newsletter consent box was the only control still painted by the operating system on every
   page. `accent-color` had tinted it sage, so it was not BLUE — but it was still the platform's
   box, with the platform's corner radius, tick and focus ring, sitting under a footer that draws
   everything else itself. Same mark the quote drawer already uses, so a visitor meets one
   checkbox on this site rather than two.

   The 44px hit area on ::before is kept exactly as it was: visible size and target size are
   different things, and only the visible half changes here. */
.rv-sub-consent input[type=checkbox]{-webkit-appearance:none;appearance:none;
  width:18px;height:18px;flex:none;margin:0;border:1.5px solid var(--border-ctl);border-radius:var(--r-control,2px);
  background:var(--surface-1);cursor:pointer;position:relative;
  transition:border-color var(--t-ctl) var(--ease),background var(--t-ctl) var(--ease)}
.rv-sub-consent input[type=checkbox]:hover{border-color:var(--sage)}
.rv-sub-consent input[type=checkbox]:checked{border-color:var(--sage);background:var(--sage)}
.rv-sub-consent input[type=checkbox]:checked::after{content:'';position:absolute;
  left:5px;top:1.5px;width:5px;height:10px;border:solid var(--on-sage);
  border-width:0 2px 2px 0;transform:rotate(42deg)}
.rv-sub-consent input[type=checkbox]:focus-visible{outline:2px solid var(--sage);outline-offset:2px}
@media(prefers-reduced-motion:reduce){
  .rv-sub-consent input[type=checkbox]{transition:none}
}

/* ==================================================== THE CANONICAL BRAND LOCKUP
   The mark and the wordmark are ONE object, so their relationship has to be a ratio, never two
   independently chosen pixel values. It was two: `shell.css` pins the footer mark at a hard 24px,
   and this file later grew the footer wordmark to clamp(20px,3vw,34px). At 1440 that left a 24px
   mark beside a 34px wordmark — a ratio of 0.71, against the header's 22/18 = 1.22 — so the same
   lockup appeared at two different weights on one page. The aspect audit passed throughout,
   because each instance was individually undistorted; what was wrong was the RELATIONSHIP.

   The mark is 1.22x the wordmark's type size everywhere, expressed in em so it can only ever
   drift if someone changes it on purpose. The asset is 552x763 and width stays `auto`, so the
   non-square proportion is carried by the file rather than restated in CSS.
   Guarded by qa/lockup_system_check.py. */
/* CORRECTION, measured. Tying the mark to `1.22em` was still wrong, because em is the type
   SIZE and a lockup is read against the CAP HEIGHT. Orbitron's caps are ~0.726em, so 1.22em put
   the mark at 1.69x cap height in the header and footer - 48% larger, relative to the letters,
   than the hero lockup that actually reads correctly at 1.14x.

   Worse, `align-items:center` centres on the LINE BOX, which includes descender space the word
   RAVENOR never uses. In the footer that pushed the mark down until it hung 14.7px BELOW the
   baseline while rising only 1.7px above the caps - the lopsided, sitting-on-the-wordmark
   composition the owner reported.

     mark height = 1.14 x cap = 1.14 x 0.726em = 0.83em
     alignment   = baseline (mark's foot ON the baseline), then nudged down 0.05em so the mark's
                   centre and the CAP BAND's centre coincide - leaving ~0.05em of overshoot above
                   the caps and below the baseline, symmetrically.

   Verified with qa/lockup_system_check.py, which now measures against cap height and asserts the
   overshoot is balanced rather than just checking the asset is undistorted. */
/* This block used to set the mark to .83em against a .72em cap - the 1.15 ratio the owner kept
   reporting as a wrong lockup. It now declares only what is local to these two surfaces (how big
   the wordmark is) and takes every proportion from the lockup system in shell.css. */
.rv-foot-lockup{font-size:clamp(20px,3vw,34px);gap:var(--brand-mark-gap,.187em)}
.rv-foot-word{font-size:1em;position:static}
.rv-foot-lockup img,.rv-hdr .brand img{height:var(--brand-mark-h,1.872em);width:auto;
  aspect-ratio:var(--brand-mark-aspect,552 / 763);flex:none;object-fit:contain;transform:none}
/* Aligning the mark's BOTTOM EDGE to the baseline hangs the whole mark off the text at the
   canonical 2.6 ratio, and centring the two cannot be made to agree across surfaces that use
   different font-sizes and line-heights. The lockup authority aligns the mark's BODY edge -
   y=552/763, where stem and block end - to the baseline instead, and the leg descends past it.
   These two surfaces declare only how big their wordmark is. See assets/brand-lockup.css. */
.rv-hdr .brand{gap:var(--brand-mark-gap,.187em)}
/* The narrow-viewport header used to pin the mark back to .83em - the 1.15 ratio again, so the
   phone kept the exact lockup the owner rejected while the desktop was corrected. The mark is
   sized by the same token at every width; only the WORDMARK gets smaller on a phone, which is
   what makes the lockup scale instead of recomposing itself. */

/* ============================================ LONG WORDS IN ARMENIAN AND RUSSIAN
   "Металлоконструкции" and "Մետաղական կոնստրուկցիաներ" are single unbreakable words far longer
   than anything English puts in a heading. At 390px the service title was rendering 398px wide
   inside a 346px column and the word was being cut mid-syllable — the page did not scroll, so
   nothing looked broken from the outside; the title was simply unreadable.

   `overflow-wrap:break-word` was already set and did not help, and the reason is the part that
   is easy to miss: break-word permits a break at paint time but does NOT change the element's
   MIN-CONTENT width, so a flex or grid item still refuses to shrink below its longest word.
   `anywhere` does change min-content, and `min-width:0` releases the automatic minimum on the
   item itself. Both are needed; either alone leaves the overflow in place.

   This is a fluid fix, not a breakpoint: it holds at any width, for any word, in any language. */
.rv-h1,.rv-h2,.rv-page-head h1,.rv-page-head h2,
.pj-card h3,.sv-grid .sv-card h3,.rv-foot-col h2{overflow-wrap:anywhere}
.rv-page-head > *,.rv-sect-head > *{min-width:0}

/* ---------------------------------------- ...AND WHAT `anywhere` COSTS, WHICH WAS NOT NOTICED
   The rule above stopped the OVERFLOW and turned it into a mid-word BREAK. Measured on the
   running page at 390px, the Armenian services heading rendered as

       ԾԱՌԱՅՈՒԹՅՈՒՆ
       ՆԵՐ

   - one word, no hyphen, split after the eleventh letter. Nothing overflowed, so every
   responsive check passed; `overflow-wrap:anywhere` had converted a defect the tests could see
   into one only a reader could. `anywhere` is the right BACKSTOP and the wrong primary fix.

   The primary fix is to size display type against the script being set. Every number below is
   measured with a DOM Range around the word itself (qa/mc_typography.py), never estimated from
   a character count:

     ԾԱՌԱՅՈՒԹՅՈՒՆՆԵՐ   401px at 40px  ->  10.03px of word per px of font
     page heading box   = viewport - 44px at 360 / 390 / 430
     largest font that fits = (vw - 44) / 10.03  ->  31.5 / 34.5 / 38.5px

   8.6vw sits under that line at every width in the range and reaches the 40px design size at
   465px, where the cap takes over - so nothing changes on any viewport that was already fine.
   Scoped with :lang() because this is a property of the SCRIPT, not of the phone: English never
   breaks here and must not be shrunk to fix a language that does. Russian headings were
   measured in the same run and do not break at h1 size, so Russian is left alone. */
@media(max-width:600px){
  html:lang(hy) .rv-h1,
  html:lang(hy) .rv-page-head h1{font-size:clamp(26px,8.6vw,40px)}
}

/* ------------------------------------------------- the subscription row's dead half
   `1fr 1fr` with the two columns stretched: the left column holds one short heading and the
   right holds a field, a button and two lines of consent, so the left column was left with
   roughly 190px of nothing under its heading while the right column ran on. A two-column grid
   only works when both columns have comparable content.

   The heading now sits at the TOP of its column rather than being stretched down it, the split
   favours the side that actually has content, and both halves are vertically centred against
   each other - so the row is one object instead of a heading marooned beside a form. */
.rv-subscription{grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);align-items:center;
  gap:clamp(28px,4vw,56px)}
.rv-subscription > *{align-self:center}
@media(max-width:760px){
  .rv-subscription{grid-template-columns:1fr;align-items:stretch;gap:22px}
}

/* ==================================================== FOOTER — THE TITLE BLOCK
   Four labelled cells in a band, the identity above them, the social marks below. See the
   comment in shell.js buildFooter for why this shape. These rules give the band its structure:
   a hairline above and between the cells, so it reads as a drawn block rather than as four
   text columns that happen to be side by side. */
.rv-foot-head{display:flex;flex-direction:column;gap:14px;padding-bottom:clamp(26px,3vw,38px)}
.rv-foot-head p{color:var(--muted);font-size:15px;line-height:1.65;max-width:46ch;margin:0}

.rv-foot-grid{grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(20px,2.6vw,40px);
  border-top:1px solid var(--border-2);padding-top:clamp(24px,2.8vw,34px)}
/* the cell divider: a hairline between columns, the way a title block is ruled */
.rv-foot-col{position:relative}
.rv-foot-col + .rv-foot-col::before{content:'';position:absolute;
  left:calc(clamp(20px,2.6vw,40px) / -2);top:2px;bottom:2px;width:1px;background:var(--border-2)}
.rv-foot-col h2{font-family:var(--font-mono);font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--faint);margin-bottom:16px;font-weight:400}

.rv-foot-cell .rv-foot-dir{margin:0}
.rv-foot-cell .rv-foot-dir a{display:block;font-size:14px;line-height:1.7;color:var(--text-rev)}
.rv-foot-cell .rv-foot-dir .d{color:var(--faint);font-size:13px}
.rv-foot-maps{display:inline-flex;align-items:center;color:var(--sage);font-size:13px;margin-top:6px}
/* hours as a small key/value table, not a monospace run with pipe separators */
.rv-foot-hours{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;margin:0;
  font-family:var(--font-mono);font-size:12.5px;line-height:1.7}
.rv-foot-hours .hk{color:var(--faint)}
.rv-foot-hours .hv{color:var(--text-rev);font-variant-numeric:tabular-nums}

@media(max-width:980px){
  .rv-foot-grid{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:clamp(26px,4vw,38px)}
  /* with two columns the rule only belongs between the pair, never at the start of a row */
  .rv-foot-col + .rv-foot-col::before{display:none}
  .rv-foot-col:nth-child(even)::before{content:'';display:block;position:absolute;
    left:calc(clamp(20px,2.6vw,40px) / -2);top:2px;bottom:2px;width:1px;background:var(--border-2)}
}
/* THE FOOTER WAS TWO PHONE SCREENS TALL. Measured at 390x844 with the four cells stacked:

     Workshop 148px + Hours 78px + Explore 279px + Direct lines 189px + three 28px gaps = 778px
     ...and the whole footer 1884px, 2.23 x the viewport.

   The owner asked for two things that look opposed - the COMPLETE contact data, and a bottom
   that is not overloaded - so the height has to come out of the LAYOUT rather than out of the
   content. Holding the two-column pairing down to phone width does exactly that: Workshop sits
   beside Hours and Explore beside Direct lines, which takes the cell block from 778px to about
   455px and hides nothing. No disclosure, no accordion, nothing folded away from a visitor who
   is at the bottom of the page precisely because they are looking for a way to get in touch.

   The single column survives below 340px, where 150px of column is genuinely too narrow for an
   address. Verified against the word-break and overflow gates at 360/375/390/430 in all three
   languages - Armenian included, which is the widest of them. */
@media(max-width:339px){
  .rv-foot-grid{grid-template-columns:1fr;row-gap:28px}
  .rv-foot-col::before,.rv-foot-col:nth-child(even)::before{display:none!important}
  .rv-foot-col + .rv-foot-col{border-top:1px solid var(--border-2);padding-top:24px}
}
@media(min-width:340px) and (max-width:560px){
  /* row-gap only: the column gap stays as the grid declares it, so the vertical hairline between
     the pair keeps sitting on the half-gap it is positioned against. */
  .rv-foot-grid{row-gap:26px}
  .rv-foot-col h2{margin-bottom:12px}
}
/* The legal bar sat 54px + 24px below the consent line, which reopened a hole at the very bottom
   of a footer that had just been tightened everywhere else. */
.rv-foot-bot{margin-top:clamp(26px,3vw,36px)}

/* ============================================== BUDGET — ONE COMPONENT, ONE QUESTION
   See quote.js: the band radios and the range slider used to be two disconnected questions,
   one of them behind a disclosure. They are one control now. These rules give it the shape:
   a titled block, the bands as selectable chips, the fine range under them. */
/* The frame came off. The block now lives inside the optional disclosure, so a border around it
   is a box drawn inside a box that has just been opened - and it was the heaviest object in the
   panel wrapped around its least-required question, which is precisely the inverted weighting the
   owner read as crowding. Space and the disclosure's own hairline separate it; nothing else needs
   to. The title, the chips and the range below are untouched. */
.rv-quote .rv-budget-block{padding:0;border:0;border-radius:0;background:none}
.rv-quote .rv-budget-top{display:flex;align-items:center;justify-content:space-between;
  gap:16px;margin-bottom:14px}
.rv-quote .rv-budget-title{font-family:var(--font-display);font-size:11.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text-rev)}

/* the bands: chips, not a radio list. The inputs stay - only their presentation changes. */
.rv-quote .rv-bands{display:flex;flex-wrap:wrap;gap:8px}
.rv-quote .rv-bands input[type=radio]{position:absolute;opacity:0;width:1px;height:1px;
  border:0;background:none;margin:0;pointer-events:none}
/* A chip is a <label> element, so it inherits `.rv-quote-body label`'s FIELD-LABEL treatment -
   11.5px uppercase with .06em tracking. That is right for "Name" and wrong for an option: it was
   rendering "Need an estimate" as "NEED AN ESTIMATE". A chip states a value, not a field name. */
.rv-quote .rv-band{display:inline-flex;align-items:center;min-height:38px;padding:8px 14px;
  text-transform:none;letter-spacing:0;
  border:1px solid var(--border-ctl);border-radius:99px;cursor:pointer;
  font-size:12.5px;line-height:1;color:var(--card-tx);white-space:nowrap;
  transition:color var(--t-ctl) var(--ease),border-color var(--t-ctl) var(--ease),
             background var(--t-ctl) var(--ease)}
.rv-quote .rv-band:hover{color:var(--text-hi);border-color:var(--chip-bd)}
.rv-quote .rv-bands input:checked + .rv-band{color:var(--on-sage);background:var(--sage);
  border-color:var(--sage)}
.rv-quote .rv-bands input:focus-visible + .rv-band{outline:2px solid var(--sage);outline-offset:2px}
/* "not sure" pins no range, so the slider stands down rather than implying an answer */
.rv-quote.budget-unsure .rv-range{opacity:.4;pointer-events:none}
.rv-quote .rv-range{transition:opacity var(--t-ctl) var(--ease)}
.rv-quote .rv-range-head{margin-bottom:8px}
.rv-quote .rv-range{margin-top:16px;padding-top:14px;border-top:1px solid var(--div)}
.rv-quote .rv-range output{font-size:12px}

/* --------------------------------------------------------------- the currency listbox
   Replaces a native <select> whose POPUP Windows draws itself, in system blue, outside the
   page - the one off-brand colour left in the product and the one no screenshot can catch. */
.rv-cur{position:relative;flex:none}
.rv-cur-btn{display:inline-flex;align-items:center;gap:10px;min-height:40px;padding:8px 12px;
  border:1px solid var(--border-field);border-radius:var(--r-control,2px);background:var(--inset);
  color:var(--text);font-family:var(--font-mono);font-size:12.5px;letter-spacing:.08em;
  cursor:pointer;transition:border-color var(--t-ctl) var(--ease)}
.rv-cur-btn:hover{border-color:var(--chip-bd)}
.rv-cur-btn:focus-visible{outline:2px solid var(--sage);outline-offset:2px}
.rv-cur-chev{width:9px;height:9px;border-right:1.4px solid var(--sage);
  border-bottom:1.4px solid var(--sage);transform:rotate(45deg) translate(-1px,-1px);
  transition:transform var(--t-ctl) var(--ease)}
.rv-cur.open .rv-cur-chev{transform:rotate(-135deg) translate(-2px,-2px)}
.rv-cur-list{position:absolute;z-index:5;top:calc(100% + 6px);right:0;min-width:110px;margin:0;
  padding:5px;list-style:none;border:1px solid var(--border-in);border-radius:10px;
  background:var(--modal);box-shadow:0 18px 44px rgba(0,0,0,.6);outline:none}
.rv-cur-list li{padding:9px 12px;border-radius:6px;cursor:pointer;
  font-family:var(--font-mono);font-size:12.5px;letter-spacing:.08em;color:var(--text-rev)}
.rv-cur-list li.at{background:rgba(171,201,176,.12);color:var(--text-hi)}
.rv-cur-list li.on{color:var(--sage)}
.rv-cur-list li[aria-selected="true"]::after{content:'';float:right;width:5px;height:9px;
  margin-top:2px;border:solid var(--sage);border-width:0 1.5px 1.5px 0;transform:rotate(42deg)}
@media(prefers-reduced-motion:reduce){
  .rv-cur-chev,.rv-quote .rv-band,.rv-quote .rv-range{transition:none}
}
/* the type chip group sits under its own title, like the budget block's */
.rv-quote .rv-bands-type{margin-top:10px}
.rv-quote .fld > .rv-budget-title{display:block;margin-bottom:2px}
/* the chip system is not quote-only: the contact form asks the same question */
.rv-bands input[type=radio]{position:absolute;opacity:0;width:1px;height:1px;
  border:0;background:none;margin:0;pointer-events:none}
.rv-band{display:inline-flex;align-items:center;min-height:38px;padding:8px 14px;
  border:1px solid var(--border-ctl);border-radius:99px;cursor:pointer;
  font-family:var(--font-body);font-size:12.5px;font-weight:400;line-height:1;
  letter-spacing:0;text-transform:none;color:var(--card-tx);white-space:nowrap;
  transition:color var(--t-ctl) var(--ease),border-color var(--t-ctl) var(--ease),
             background var(--t-ctl) var(--ease)}
.rv-band:hover{color:var(--text-hi);border-color:var(--chip-bd)}
.rv-bands input:checked + .rv-band{color:var(--on-sage);background:var(--sage);border-color:var(--sage)}
.rv-bands input:focus-visible + .rv-band{outline:2px solid var(--sage);outline-offset:2px}
@media(pointer:coarse){ .rv-band{min-height:44px} }

/* ============================================================ THE CLOSING BAND
   Measured across the six public routes, every page except the homepage rendered as ONE flat
   field: three to five transparent sections and a footer, two tonal grounds in total, against the
   homepage's four. That is the whole of "the secondary pages feel weaker and flatter" - the
   homepage has depth and they have none.

   Rather than tint sections at random, the depth is put where the page is actually asking for
   something. Every secondary route ends the same way - a rule, a heading, a line of lead copy and
   the quote button - so that closing moment becomes one repeated device: a full-bleed green-black
   wash, the treatment the owner approved from production. It is nearly black; the green is in the
   TONE, not on the surface, and the only literal brand colour is a hairline of light along the top
   edge and the button itself.

   Full-bleed uses the same -50vw escape as .rv-bg, clipped by body{overflow-x:clip}, so it can
   never produce a horizontal scrollbar. The band replaces the .rv-rule that used to sit above the
   heading: its own lit top edge is that line, and drawing both would be two rules doing one job. */
.rv-sect-cta{position:relative;isolation:isolate;
  padding-block:clamp(54px,6.4vw,92px);margin-top:clamp(36px,5vw,72px)}
.rv-sect-cta::before{content:'';position:absolute;z-index:-1;pointer-events:none;
  top:0;bottom:0;left:-50vw;right:-50vw;
  background:
    radial-gradient(108% 128% at 50% 0%,rgba(171,201,176,.055),rgba(171,201,176,0) 62%),
    linear-gradient(180deg,#0C120E 0%,#0A0F0C 56%,var(--base) 100%);
  border-top:1px solid rgba(171,201,176,.17)}
/* a drafting tick at the band's own left edge, on the content rail - the same vocabulary the
   process page uses, at a size that reads as a registration mark rather than decoration */
.rv-sect-cta::after{content:'';position:absolute;z-index:-1;pointer-events:none;
  left:0;top:0;width:44px;height:1px;background:var(--sage);opacity:.55}
.rv-sect-cta > .rv-rule{display:none}
.rv-sect-cta .rv-sect-head{margin-top:0!important}
@media(prefers-reduced-motion:no-preference){
  .rv-sect-cta .rv-btn{transition:transform var(--t-ctl) var(--ease),background var(--t-ctl) var(--ease)}
}

/* ==============================================================================================
   OWNER VISUAL ACCEPTANCE — VERIFIED SUBSCRIPTION JOURNEY
   The same dark/sage surface anatomy serves entry, verification, verified management and outcomes.
   Business state still comes exclusively from the subscription authority in server/subscription.py. */
.rv-subscription{
  position:relative;overflow:hidden;isolation:isolate;
  margin-top:clamp(54px,7vw,90px);padding:clamp(28px,4vw,52px);
  border:1px solid rgba(171,201,176,.18);border-radius:var(--r-surface,12px);
  background:
    radial-gradient(90% 160% at 8% 0,rgba(171,201,176,.10),transparent 56%),
    linear-gradient(145deg,rgba(18,24,20,.96),rgba(9,12,10,.98));
  box-shadow:inset 0 1px 0 rgba(236,246,238,.055),0 28px 80px -58px rgba(0,0,0,.95);
  grid-template-columns:minmax(0,.78fr) minmax(360px,1.22fr);align-items:stretch;
  gap:clamp(32px,5vw,72px)
}
.rv-subscription::after{content:'';position:absolute;left:0;top:0;width:34%;height:1px;
  background:linear-gradient(90deg,var(--sage),transparent);opacity:.8}
.rv-subscription>h2{align-self:start;margin:7px 0 0;max-width:12ch;
  font:500 clamp(25px,2.6vw,38px)/1.14 var(--font-body);letter-spacing:-.035em}
.rv-sub-form{position:relative;align-self:stretch;padding:clamp(22px,2.8vw,32px);
  border:1px solid rgba(171,201,176,.13);border-radius:10px;background:rgba(3,6,4,.34);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.025)}
.rv-sub-form::before{content:'01 / 03';display:block;margin-bottom:18px;color:var(--sage);
  font:500 10px/1 var(--font-mono);letter-spacing:.18em}
.rv-sub-form[data-step="verify"]::before{content:'02 / 03'}
.rv-sub-form[data-step="manage"]::before,.rv-sub-form[data-step="confirm"]::before,
.rv-sub-form[data-step="complete"]::before{content:'03 / 03'}
/* `:not(.rv-sub-consent)` because the consent control is ALSO a direct-child <label>, and this is
   field-label treatment: 11px, tracked out, upper case. Applied to the consent it set a two-line
   legal sentence in spaced capitals, which is the hardest way to present the one sentence on this
   panel a visitor is actually being asked to agree to. */
.rv-sub-form>label:not(.rv-sub-consent),.rv-manage-form>label{font:500 11px/1.4 var(--font-body);
  letter-spacing:.08em;text-transform:uppercase;color:var(--text-rev);margin-bottom:9px}
.rv-sub-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;border-radius:0}
.rv-sub-row input,.rv-manage-form>input{
  width:100%;min-height:var(--ctl-h-field,52px);padding:13px 15px;border:1px solid rgba(171,201,176,.25);
  border-radius:var(--r-control,2px);background:rgba(5,8,6,.78);color:var(--text-hi);
  font:16px/1.3 var(--font-body);caret-color:var(--sage);
  transition:border-color var(--t-fast),box-shadow var(--t-fast),background var(--t-fast)}
.rv-sub-row input:hover,.rv-manage-form>input:hover{border-color:rgba(171,201,176,.42)}
.rv-sub-row input:focus-visible,.rv-manage-form>input:focus-visible{
  outline:0;border-color:var(--sage);box-shadow:0 0 0 3px rgba(171,201,176,.11);
  background:rgba(9,14,11,.96)}
/* Matches the FIELD beside it, from the same token, which is the whole reason
   this row is allowed a height of its own. */
.rv-sub-row .rv-btn{min-height:var(--ctl-h-field,52px);padding-inline:clamp(18px,2vw,26px)}
.rv-sub-helper{margin:14px 0 0;color:var(--muted);font-size:13px;line-height:1.65}
.rv-sub-form .rv-sub-consent{margin:18px 0 0;padding-top:16px;border-top:1px solid var(--border-3);
  font-size:12px;line-height:1.65;color:var(--faint)}
.rv-sub-consent input{width:18px;height:18px;margin-top:1px}
.rv-sub-status,.rv-manage-status{min-height:0;margin:14px 0 0;color:var(--muted);
  font-size:13px;line-height:1.65}
.rv-sub-status:empty,.rv-manage-status:empty{display:none}
.rv-sub-status[data-tone="error"],.rv-manage-status[data-tone="error"]{display:block;color:#efb4aa;
  padding:11px 13px;border-left:2px solid #b86d62;background:rgba(117,47,40,.13)}
.rv-sub-status[data-tone="success"],.rv-manage-status[data-tone="success"]{color:var(--sage-bright)}
.rv-sub-resend{display:inline-flex;align-items:center;justify-content:center;min-height:44px;
  margin-top:10px;padding:6px 0;color:var(--sage);font-size:12px;text-decoration:underline;
  text-underline-offset:4px}
.rv-sub-resend:disabled{color:var(--faint);text-decoration:none;cursor:default}
/* The owner's note was that this control was AWKWARDLY EXPOSED, not that the capability should
   go: it is how somebody who is already subscribed reaches management without first guessing that
   the Subscribe field would take them there, and the assistant deep-links to the same dialog.
   Hiding it with display:none also silently broke the Admin subscription test, which clicks it.
   So it is designed instead of removed - a quiet text control on its own rule, under the primary
   action, reading as an aside rather than as a second call to action. */
.rv-sub-manage{display:inline-flex;align-items:center;min-height:44px;margin-top:18px;
  padding:6px 0;color:var(--muted);font-size:12px;line-height:1.5;text-align:left;
  text-decoration:underline;text-decoration-color:var(--border-2);text-underline-offset:5px;
  transition:color var(--t-fast),text-decoration-color var(--t-fast)}
.rv-sub-manage:hover{color:var(--text-hi);text-decoration-color:var(--sage)}
.rv-sub-manage:focus-visible{text-decoration-color:var(--sage)}
.rv-manage-actions{display:flex;align-items:center;flex-wrap:wrap;gap:10px;margin-top:20px}
.rv-manage-keep,.rv-btn-quiet{min-height:44px;padding:10px 14px;color:var(--text-rev);
  border:1px solid transparent;font-size:12px}
.rv-manage-keep:hover,.rv-btn-quiet:hover{color:var(--text-hi);border-color:var(--border-2)}
.rv-manage-actions>.rv-btn:not(.rv-btn-solid){color:#efb4aa;border-color:rgba(184,109,98,.48)}
.rv-manage-actions>.rv-btn:not(.rv-btn-solid):hover{background:rgba(117,47,40,.18)}
/* ONE outcome card, five tones. A tone changes two colours and the glyph inside the mark, and
   nothing else - so "you are subscribed", "you are unsubscribed" and "leave the list?" are
   recognisably the same object in the same place, which is what lets the visitor read the
   difference between them instead of re-reading the whole panel. */
.rv-sub-status[data-result],.rv-manage-status[data-result]{
  --tone:171,201,176;                 /* sage: confirmed, and the resting state of the journey */
  --tone-edge:.30;--tone-mark:.58;--tone-fill:.15;--tone-glow:0 0 36px rgba(171,201,176,.20);
  display:grid;grid-template-columns:54px 1fr;gap:4px 16px;align-items:center;
  padding:22px;margin-top:4px;min-height:132px;
  border:1px solid rgba(var(--tone),var(--tone-edge));border-radius:10px;
  background:linear-gradient(135deg,rgba(var(--tone),var(--tone-fill)),rgba(var(--tone),.035));
  color:var(--text-hi)}
/* Amber, and only for a decision the visitor has not taken yet, or a state that needs a human. */
[data-result="warning"]{--tone:216,183,131;--tone-edge:.34;--tone-mark:.62;--tone-fill:.13;
  --tone-glow:none}
/* No longer on the list, and nothing found: true, not a failure. Neither earns sage nor amber. */
[data-result="unsubscribed"],[data-result="neutral"]{--tone:161,173,165;--tone-edge:.26;
  --tone-mark:.46;--tone-fill:.085;--tone-glow:none}
.rv-sub-result-mark{grid-row:1/3;width:50px;height:50px;display:grid;place-items:center;
  border:1px solid rgba(var(--tone),var(--tone-mark));border-radius:50%;
  background:radial-gradient(circle,rgba(var(--tone),.22),rgba(var(--tone),.05));
  box-shadow:var(--tone-glow)}
/* THE SECOND DELIBERATE EXCEPTION to --ico-stroke. This mark is 28px inside a 50px ring and
   a visitor sees it once, after something has either worked or failed - it is the largest and
   most singular mark in the product, and at the product weight a 28px tick reads as thin and
   provisional rather than as a confirmation. Heavier on purpose. */
.rv-sub-result-mark svg{width:28px;height:28px;fill:none;stroke:rgb(var(--tone));
  stroke-width:2.1;stroke-linecap:round;stroke-linejoin:round}
/* The brand sage, not the pale tint used for body emphasis: at 28px the tint reads as grey and
   the one element that is supposed to say "Ravenor confirmed this" said nothing at all. */
[data-result="success"] .rv-sub-result-mark svg,
[data-result="active"] .rv-sub-result-mark svg{stroke:var(--sage)}
.rv-sub-result-title{display:block;font:500 clamp(20px,2vw,26px)/1.2 var(--font-body);
  letter-spacing:-.025em;color:var(--text-hi)}
.rv-sub-result-copy{display:block;color:var(--muted);font-size:13px;line-height:1.65}
/* Arriving at an outcome is a moment; it is given one, once, and it is small. The card settles
   rather than bounces, and the mark draws a beat behind it. Nothing loops, nothing celebrates. */
@media(prefers-reduced-motion:no-preference){
  .rv-sub-status[data-result],.rv-manage-status[data-result]{animation:rv-outcome .42s var(--ease) both}
  .rv-sub-result-mark{animation:rv-outcome-mark .5s var(--ease) .08s both}
}
/* Once the journey has produced an outcome, the fields are gone - so the panel that framed them is
   framing nothing, and the outcome card sits inside a second identical dark box. Two nested cards
   is what made a finished success state read as a placeholder. The panel dissolves and the card
   becomes the panel. */
.rv-sub-form[data-step="manage"],.rv-sub-form[data-step="confirm"],
.rv-sub-form[data-step="complete"]{padding:0;border-color:transparent;background:none;
  box-shadow:none}
.rv-sub-form[data-step="manage"]::before,.rv-sub-form[data-step="confirm"]::before,
.rv-sub-form[data-step="complete"]::before{margin-bottom:13px}
@keyframes rv-outcome{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
@keyframes rv-outcome-mark{from{opacity:0;transform:scale(.86)}to{opacity:1;transform:none}}

/* Native dialog supplies the focus trap and Escape behaviour; Ravenor supplies its visual anatomy. */
html.rv-modal-open{overflow:hidden}
dialog.rv-manage{inset:0;margin:auto;width:min(580px,calc(100vw - 32px));max-width:none;
  max-height:min(760px,calc(100dvh - 32px));overflow:auto;padding:0;color:var(--text-hi);
  border:1px solid rgba(171,201,176,.24);border-radius:12px;
  background:
   radial-gradient(100% 70% at 0 0,rgba(171,201,176,.11),transparent 58%),
   linear-gradient(150deg,#121713,#090c0a 72%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.055),0 30px 110px rgba(0,0,0,.72);
  font-family:var(--font-body)}
dialog.rv-manage::backdrop{background:rgba(2,4,3,.64);backdrop-filter:blur(10px) saturate(.8);
  -webkit-backdrop-filter:blur(10px) saturate(.8)}
.rv-manage-head{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;
  padding:clamp(24px,4vw,38px) clamp(24px,4.5vw,42px) 0}
.rv-manage-head h2{margin:0;max-width:14ch;font:500 clamp(26px,4vw,38px)/1.12 var(--font-body);
  letter-spacing:-.035em;text-transform:none;color:var(--text-hi)}
.rv-manage-close{width:44px;height:44px;display:grid;place-items:center;flex:none;margin:-6px -8px 0 0;
  border:1px solid var(--border-2);border-radius:50%;color:var(--muted);font:300 27px/1 var(--font-body);
  transition:color var(--t-fast),border-color var(--t-fast),transform var(--t-fast)}
.rv-manage-close:hover{color:var(--text-hi);border-color:var(--sage);transform:rotate(4deg)}
.rv-manage-intro{margin:18px clamp(24px,4.5vw,42px) 0;max-width:47ch;color:var(--muted);
  font-size:14px;line-height:1.7}
.rv-manage-form{position:relative;padding:clamp(24px,4.5vw,42px);padding-top:30px}
.rv-manage-form::before{content:'01 / 03';display:block;margin-bottom:20px;color:var(--sage);
  font:500 10px/1 var(--font-mono);letter-spacing:.18em}
.rv-manage-form[data-step="verify"]::before{content:'02 / 03'}
.rv-manage-form[data-step="manage"]::before,.rv-manage-form[data-step="confirm"]::before,
.rv-manage-form[data-step="complete"]::before{content:'03 / 03'}
.rv-manage-form>.rv-btn-solid{width:100%;min-height:50px;margin-top:14px}
.rv-manage-status[data-result]{margin-top:0}
.rv-manage-form .rv-manage-actions{padding-top:4px}
@media(max-width:760px){
 .rv-subscription{grid-template-columns:1fr;gap:24px;padding:26px 22px}
 .rv-subscription>h2{max-width:18ch;margin:0}
}
@media(max-width:520px){
 .rv-subscription{margin-inline:-10px;padding:24px 18px;border-radius:10px}
 .rv-sub-form{padding:20px 16px}
 .rv-sub-row{grid-template-columns:1fr}
 .rv-sub-row .rv-btn{width:100%}
 .rv-sub-status[data-result],.rv-manage-status[data-result]{grid-template-columns:42px 1fr;
   gap:5px 12px;padding:18px;min-height:122px}
 .rv-sub-result-mark{width:40px;height:40px}
 .rv-sub-result-mark svg{width:23px;height:23px}
 dialog.rv-manage{width:100%;height:100dvh;max-height:100dvh;border-radius:0;border-inline:0}
 .rv-manage-head{padding:22px 20px 0}.rv-manage-head h2{font-size:28px}
 .rv-manage-intro{margin:14px 20px 0}.rv-manage-form{padding:24px 20px max(24px,env(safe-area-inset-bottom))}
}
@media(prefers-reduced-motion:reduce){
 .rv-manage-close,.rv-sub-row input,.rv-manage-form>input{transition:none}
 .rv-manage-close:hover{transform:none}
}