/*
 * Portfolio A — shared stylesheet.
 *
 * Ported from the Claude Design document `Portfolio A.dc.html`, whose styling
 * was almost entirely inline. Patterns that repeat three or more times with
 * identical declarations are promoted to classes here; genuine one-offs (the
 * home h1 clamp, the blinking cursor, the marquee track, per-case max-widths)
 * stay inline in the pages so this file does not fill with single-use rules.
 */

/* ---- foundation ------------------------------------------------------- */
html{scroll-behavior:smooth}
body{margin:0;background:#0C0C0B;color:#F2F1EC;font-family:'Space Grotesk',sans-serif;-webkit-font-smoothing:antialiased}
a{color:#F2F1EC;text-decoration:none}
a:hover{color:#D8FF3E}
::selection{background:#D8FF3E;color:#0C0C0B}

.mono{font-family:'IBM Plex Mono',monospace}
.lime{color:#D8FF3E}

/* Cross-document transition, so navigating between pages keeps the animated
   feel the single-page original had. No JS; unsupported browsers just load. */
@view-transition{navigation:auto}

/* ---- animation ------------------------------------------------------- */
@keyframes marq{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@keyframes riseIn{from{opacity:0;transform:translateY(110%)}to{opacity:1;transform:none}}
@keyframes blink{0%,49%{opacity:1}50%,100%{opacity:0}}
/* The mask must clip the BOTTOM — riseIn starts the text at translateY(110%) and
   lifts it into place — but line-height .98 leaves the box shorter than the
   font's descent, so "g", "y" and "p" lost their tails. Growing the mask's own
   padding puts the descender inside the clip, and a matching negative margin
   keeps the line rhythm unchanged. Padding on the child would not work: it
   grows the line box, which the child's own negative margin then collapses. */
.mask{overflow:hidden;padding-bottom:.22em;margin-bottom:-.22em}
.mask>span{display:inline-block;animation:riseIn .9s cubic-bezier(.2,.8,.2,1) both}
.rev{opacity:0;transform:translateY(36px);transition:opacity .8s cubic-bezier(.2,.8,.2,1),transform .8s cubic-bezier(.2,.8,.2,1)}
.rev.inview{opacity:1;transform:none}
.d1{transition-delay:.08s}
.d2{transition-delay:.16s}
.d3{transition-delay:.24s}

/* Without JS nothing would ever gain .inview, so opt out of the reveal
   entirely and show the content. */
html:not(.js) .rev{opacity:1;transform:none}

/* ---- chrome ---------------------------------------------------------- */
header{position:sticky;top:0;z-index:50;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:18px 40px;background:rgba(12,12,11,0.82);backdrop-filter:blur(12px);border-bottom:1px solid rgba(242,241,236,0.12)}
.wordmark{font-weight:600;font-size:16px;letter-spacing:-0.01em}
.wordmark span{color:#D8FF3E}
/* Below ~430px the full name wraps onto a second line and the sticky header
   doubles in height. Measured: wraps at 390, fits from 430 — 480 leaves margin.
   The surname drops, the lime dot stays attached to the first name. */
.wm-last{color:inherit}
@media (max-width:480px){ .wm-last{display:none} }
header nav{display:flex;align-items:center;gap:26px;font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.08em}
.lang{display:flex;align-items:center;gap:8px;padding-left:4px}
.lang a{color:rgba(242,241,236,0.45)}
.lang a.on{color:#D8FF3E}
.lang i{font-style:normal;color:rgba(242,241,236,0.25)}

footer{border-top:1px solid rgba(242,241,236,0.14);padding:88px 40px 40px}
.mailto{display:block;font-size:clamp(30px,6vw,96px);font-weight:500;letter-spacing:-0.04em;line-height:1.05}
.foot-note{margin:32px 0 0;max-width:44ch;font-size:16px;line-height:1.6;color:rgba(242,241,236,0.55)}
.foot-bar{display:flex;justify-content:space-between;align-items:baseline;gap:24px;flex-wrap:wrap;margin-top:72px;padding-top:24px;border-top:1px solid rgba(242,241,236,0.14);font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.08em}
.foot-bar a{color:rgba(242,241,236,0.7)}
.foot-links{display:flex;gap:28px}

/* ---- labels ---------------------------------------------------------- */
.lbl{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.1em;color:rgba(242,241,236,0.5)}
.lbl-t{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.08em;color:rgba(242,241,236,0.5)}
.eyebrow{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.1em;color:#D8FF3E;margin-bottom:16px}
.back{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.08em;color:rgba(242,241,236,0.6)}
.sec-head{display:flex;justify-content:space-between;font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.1em;color:rgba(242,241,236,0.5)}

/* ---- grids ----------------------------------------------------------- */
.g2{display:grid;grid-template-columns:1fr 1fr;gap:28px}
.g3{display:grid;grid-template-columns:repeat(3,1fr);gap:28px}
.g-wide{gap:64px;padding:24px 0}

/* ---- hero ------------------------------------------------------------ */
.hero{padding:100px 40px 64px}
.hero-meta{font-size:12px;letter-spacing:0.12em;display:flex;gap:32px;flex-wrap:wrap;margin-bottom:40px}
.hero-h1{margin:0;font-size:clamp(40px,7vw,104px);line-height:0.98;letter-spacing:-0.04em;font-weight:500}
.hero-lede{margin:44px 0 0;max-width:52ch;font-size:18px;line-height:1.6;color:rgba(242,241,236,0.65);
  animation:riseIn .9s .25s cubic-bezier(.2,.8,.2,1) both}

/* ---- work list ------------------------------------------------------- */
.hrow{position:relative;display:flex;justify-content:space-between;align-items:center;gap:20px;padding:34px 40px;border-bottom:1px solid rgba(242,241,236,0.12);transition:background .3s,padding-left .3s}
.hrow:hover{background:rgba(216,255,62,0.05);padding-left:56px}
.hrow .himg{position:absolute;right:220px;top:50%;width:260px;height:170px;object-fit:cover;border-radius:8px;opacity:0;transform:translateY(-50%) rotate(-3deg) scale(.85);transition:all .35s cubic-bezier(.2,.8,.2,1);pointer-events:none;z-index:2}
.hrow:hover .himg{opacity:1;transform:translateY(-50%) rotate(-3deg) scale(1)}
/* nth-of-type, not nth-child: immune to anything non-row landing in the list */
.hrow:nth-of-type(even) .himg{transform:translateY(-50%) rotate(2.5deg) scale(.85)}
.hrow:nth-of-type(even):hover .himg{transform:translateY(-50%) rotate(2.5deg) scale(1)}
/* The boxes are centred correctly, but the arrow's INK is not: → sits entirely
   above the baseline (measured ascent 11.45 / descent -3.01 at 20px), so its
   ink centre lands ~0.19em above the meta text's. Measured at both sizes in use
   — 0.187em at 20px, 0.200em at 26px — so one em-based offset serves both.
   Uses position, not transform: transform drives the hover animation. */
.arr{position:relative;top:0.19em}
.hrow .arr{opacity:0;transform:translateX(-10px);transition:all .3s;color:#D8FF3E}
.hrow:hover .arr{opacity:1;transform:none}
.ttl{font-size:48px;font-weight:500;letter-spacing:-0.03em}
.num{font-family:'IBM Plex Mono',monospace;font-size:13px;color:rgba(242,241,236,0.4);margin-right:20px;vertical-align:14px}
.rmeta{display:flex;align-items:center;gap:18px}

/* ---- media -----------------------------------------------------------
 * The design used fixed 560px / 440px frames with object-fit:cover. That is
 * fine for photography but wrong for screenshots: it silently ate the top and
 * bottom of every UI shot, and on a phone it cropped away most of the width.
 * Containers now take their height from the image's own aspect, so nothing is
 * ever cropped. Paired images share an aspect, so a row still lines up.
 */
.cov,.cov2{border-radius:10px;overflow:hidden}
.zoomimg{display:block;width:100%;height:auto;transition:transform .6s cubic-bezier(.2,.8,.2,1)}
.zoomwrap:hover .zoomimg{transform:scale(1.03)}

/* ---- case study shell ------------------------------------------------ */
.case-head{padding:64px 40px 56px;border-bottom:1px solid rgba(242,241,236,0.12)}
.case-meta{display:flex;gap:32px;flex-wrap:wrap;margin-top:40px}
.case-title{margin:24px 0 0;font-size:clamp(36px,6vw,88px);line-height:1.02;letter-spacing:-0.04em;font-weight:500;max-width:18ch}
.case-lede{margin:32px 0 0;max-width:54ch;font-size:18px;line-height:1.6;color:rgba(242,241,236,0.65)}
.case-body{padding:40px;display:flex;flex-direction:column;gap:40px}
.body-copy{margin:0;font-size:17px;line-height:1.65;color:rgba(242,241,236,0.75)}
.stack{display:flex;gap:8px;flex-wrap:wrap;margin-top:26px}
.stack span{font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:0.06em;padding:5px 10px;border:1px solid rgba(242,241,236,0.22);border-radius:999px;color:rgba(242,241,236,0.6)}

/* Pipeline / architecture diagrams, rendered as markup rather than baked into a
   PNG: the text scales, stays selectable and searchable, and never gets cropped.
   Used where a project has no UI worth photographing. */
.flow{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.flow .step{border:1px solid rgba(242,241,236,0.18);border-radius:10px;padding:18px 18px 20px;background:rgba(242,241,236,0.02)}
.flow .step b{display:block;font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:0.12em;text-transform:uppercase;color:#D8FF3E;margin-bottom:10px;font-weight:500}
.flow .step p{margin:0;font-size:14px;line-height:1.6;color:rgba(242,241,236,0.7)}
.flow .step.key{border-color:rgba(216,255,62,0.45);background:rgba(216,255,62,0.05)}
/* Monospace readouts are authored as aligned columns, so the source newlines and
   run of spaces ARE the layout: without white-space:pre the browser collapses
   them and the table reads as one wrapped paragraph. That is also what the
   overflow-x is for — a pre block wider than the box scrolls inside it. */
.filters{margin:0;font-family:'IBM Plex Mono',monospace;font-size:13px;line-height:2;color:rgba(242,241,236,0.55);border:1px solid rgba(242,241,236,0.14);border-radius:10px;padding:20px 22px;white-space:pre;overflow-x:auto}
.filters b{color:#D8FF3E;font-weight:500}
@media (max-width:840px){
  .filters{font-size:11px;padding:14px}
}

.stats{border-top:1px solid rgba(242,241,236,0.12);padding-top:40px}
.stat-n{font-size:44px;font-weight:500;letter-spacing:-0.02em;color:#D8FF3E}
.stat-l{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.08em;color:rgba(242,241,236,0.5);margin-top:8px}

.next{display:flex;justify-content:space-between;align-items:baseline;gap:16px;flex-wrap:wrap;border-top:1px solid rgba(242,241,236,0.25);padding:32px 0 16px}
.next b{font-size:32px;font-weight:500}

/* ---- services / about ------------------------------------------------ */
.svc{border-top:1px solid rgba(242,241,236,0.25);padding-top:20px}
.svc h3{margin:0 0 12px;font-size:22px;font-weight:500}
.svc p{margin:0;font-size:15px;line-height:1.6;color:rgba(242,241,236,0.6)}
.svc .eyebrow{font-size:12px;margin-bottom:16px}
.about{padding:64px 40px;border-top:1px solid rgba(242,241,236,0.12);display:flex;gap:40px;align-items:flex-start;flex-wrap:wrap}
.about img{width:96px;height:96px;border-radius:50%;object-fit:cover;flex-shrink:0}
.about p{margin:0 0 18px;max-width:62ch;font-size:18px;line-height:1.6;color:rgba(242,241,236,0.75)}
.about .roles{font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:0.1em;color:rgba(242,241,236,0.45)}

/* ---- responsive ------------------------------------------------------ */
@media (max-width:840px){
  main>section,footer,header,.about{padding-left:20px !important;padding-right:20px !important}
  /* #work is the one full-bleed section: it has no padding of its own on
     desktop, its rows carry theirs, and the separators run edge to edge. The
     blanket rule above was insetting the whole list and, because .sec-head
     keeps its own 40px, pushing the section label 20px further in than the
     rows it labels. Opt the section out and shrink the label's padding to
     match a row. */
  #work{padding-left:0 !important;padding-right:0 !important}
  #work .sec-head{padding:40px 20px 20px !important}
  .g2,.g3{grid-template-columns:1fr !important;gap:28px !important}
  .g-wide{gap:28px !important}
  .case-body{padding:20px !important;gap:24px !important}
  header{padding:14px 20px !important}
  header nav{gap:12px !important;font-size:10px !important}
  .lang{gap:6px}

  /* First screen on a phone. The desktop 100px of top padding pushed the intro
     paragraph past the fold at 390x660, so the page opened on a sentence cut in
     half; 36px fixed that but left the eyebrow sitting on the header. 64px
     clears the header properly and still ends the paragraph around 490px, so
     even a 560px-tall viewport shows the whole intro plus the marquee under it
     as a cue that there is more. */
  .hero{padding:64px 20px 44px}
  .hero-meta{font-size:10px;gap:6px 14px;margin-bottom:22px}
  /* The tagline is three deliberate lines, and what broke them on a phone is the
     desktop clamp's 40px FLOOR, not its slope: 7vw alone never overflows either
     language above ~142px. Measured at 40px against the 335px column of a 375px
     screen, "designed and built" wants 8.33em and just fits, but «Цифровые
     продукты —» wants 10.25em and wraps — three lines become six, with the
     blinking cursor orphaned on a seventh. So keep the 7vw slope, which stays
     continuous with the desktop size, and drop the floor to what each language
     can actually hold at 320px: 33.6px of room for English, 27.3px for Russian.
     Holds from 307px up; below that the floors win and the phrases wrap again,
     which is narrower than any current phone and deliberately not chased. */
  .hero-h1{font-size:clamp(30px,7vw,104px)}
  html[lang="ru"] .hero-h1{font-size:clamp(26px,7vw,104px)}
  .hero-lede{margin-top:26px;font-size:16px}

  /* Work rows: a 48px title beside right-aligned meta does not fit a phone, so
     stack them into a left-aligned block instead of letting flex squeeze. */
  .hrow{flex-direction:column;align-items:flex-start;gap:10px;padding:22px 20px !important}
  .hrow:hover{padding-left:20px !important}
  .hrow .himg{display:none}
  .hrow .ttl{font-size:30px !important;line-height:1.05;display:block}
  .num{display:block;margin:0 0 6px;vertical-align:baseline;font-size:11px}
  /* Stretch the meta row to the full column width so the arrow always lands on
     the right edge. Left to itself the arrow trails the text, which parks it
     mid-row on short meta and at the edge on meta that wraps — the rows then
     read as misaligned against each other. */
  .rmeta{gap:12px;width:100%;justify-content:space-between}
  .lbl-t{font-size:10px}
  /* The 0.19em nudge that centres the arrow's ink on desktop is measured against
     a 12px label; here the label is 10px and align-items:center already lands
     both ink centres on the same line, so the nudge just drops the arrow 3.8px
     below the technologies beside it. Back to zero. */
  .arr{opacity:1 !important;transform:none !important;font-size:20px !important;top:0}

  .flow{grid-template-columns:1fr;gap:12px}
  .filters{font-size:11px;padding:14px}
  .case-meta{gap:14px 20px;margin-top:28px}
  .stack{gap:6px}
  .stack span{font-size:10px;padding:4px 8px}
}
