Repository: omizha/sdc-stock
Pull request #35: Feat: 모달 UI 작업 및 배경없는 동물 이미지 추가
Author: login: JANGSEYEONG
Created: 2025-03-08T17:00:12Z | Merged: 2025-03-09T13:29:02Z

# 작업 내용

## 배경 없는 동물 이미지 추가
- 배경 없는 동물 이미지 10개 추가 (no_bg_animal 폴더)

## 모달 UI 변경
- Ant Design 테마, 모달 컴포넌트 설정 업데이트
- "추천 대화상대", "정보 뽑기", "대출하기" 모달 UI 개선
  - 파트너 추천 화면에 아바타 영역 추가
  <img width="1494" alt="image" src="https://github.com/user-attachments/assets/3204f95c-2966-40db-94b8-219f1145bacf" />


## 정보 탭
  - "임박" 텍스트 색상 조정
         <img width="400" alt="image" src="https://github.com/user-attachments/assets/f8effeea-51ff-4ec6-ac3b-bccbfcf5cdba" />
  - 정보 탭 하단에 패딩 추가 (정보뽑기 버튼에 카드가 가려짐)

## 파티 카드 리스트, 헤더 타이틀 영역 반응형 처리

- 코멘트 참고: https://github.com/omizha/sdc-stock/pull/35#issuecomment-2708483798



Diff:
diff --git a/app/koi-client/public/no_bg_animal/cat.webp b/app/koi-client/public/no_bg_animal/cat.webp
new file mode 100644
index 00000000..acef28ff
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/cat.webp differ
diff --git a/app/koi-client/public/no_bg_animal/dog.webp b/app/koi-client/public/no_bg_animal/dog.webp
new file mode 100644
index 00000000..6380c699
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/dog.webp differ
diff --git a/app/koi-client/public/no_bg_animal/dragon.webp b/app/koi-client/public/no_bg_animal/dragon.webp
new file mode 100644
index 00000000..71167345
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/dragon.webp differ
diff --git a/app/koi-client/public/no_bg_animal/fox.webp b/app/koi-client/public/no_bg_animal/fox.webp
new file mode 100644
index 00000000..c9bad25a
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/fox.webp differ
diff --git a/app/koi-client/public/no_bg_animal/hamster.webp b/app/koi-client/public/no_bg_animal/hamster.webp
new file mode 100644
index 00000000..98b14ec5
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/hamster.webp differ
diff --git a/app/koi-client/public/no_bg_animal/honeyBee.webp b/app/koi-client/public/no_bg_animal/honeyBee.webp
new file mode 100644
index 00000000..a42dbae7
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/honeyBee.webp differ
diff --git a/app/koi-client/public/no_bg_animal/otter.webp b/app/koi-client/public/no_bg_animal/otter.webp
new file mode 100644
index 00000000..f373e87c
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/otter.webp differ
diff --git a/app/koi-client/public/no_bg_animal/rabbit.webp b/app/koi-client/public/no_bg_animal/rabbit.webp
new file mode 100644
index 00000000..a2a4ea6a
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/rabbit.webp differ
diff --git a/app/koi-client/public/no_bg_animal/tiger.webp b/app/koi-client/public/no_bg_animal/tiger.webp
new file mode 100644
index 00000000..95e9c6c5
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/tiger.webp differ
diff --git a/app/koi-client/public/no_bg_animal/wolf.webp b/app/koi-client/public/no_bg_animal/wolf.webp
new file mode 100644
index 00000000..21f1e947
Binary files /dev/null and b/app/koi-client/public/no_bg_animal/wolf.webp differ
diff --git a/app/koi-client/src/Global.tsx b/app/koi-client/src/Global.tsx
index 42c1f11d..7b47cb57 100644
--- a/app/koi-client/src/Global.tsx
+++ b/app/koi-client/src/Global.tsx
@@ -67,7 +67,17 @@ const Global: React.FC = () => {
     <QueryClientProvider>
       <ConfigProvider
         theme={{
+          components: {
+            Modal: {
+              contentBg: '#1f2028',
+              headerBg: '#1f2028',
+              titleColor: '#ffffff',
+              titleFontSize: 18,
+            },
+          },
           token: {
+            colorIcon: '#A2A2A2',
+            colorIconHover: '#888888',
             fontFamily: 'DungGeunMo',
           },
         }}
diff --git a/app/koi-client/src/component-presentation/Card.tsx b/app/koi-client/src/component-presentation/Card.tsx
index e6db9fd4..487cbbf3 100644
--- a/app/koi-client/src/component-presentation/Card.tsx
+++ b/app/koi-client/src/component-presentation/Card.tsx
@@ -49,6 +49,7 @@ const ContainerTitle = styled.div`
 const ContainerBolder = styled.div`
   font-size: 24px;
   line-height: 22px;
+  font-weight: 400;
 `;
 
 export default Card;
diff --git a/app/koi-client/src/component-presentation/Header.tsx b/app/koi-client/src/component-presentation/Header.tsx
index 935f5b1c..2be689c6 100644
--- a/app/koi-client/src/component-presentation/Header.tsx
+++ b/app/koi-client/src/component-presentation/Header.tsx
@@ -1,4 +1,4 @@
-import { styled } from '@linaria/react';
+import styled from '@emotion/styled';
 import { Avatar } from 'antd';
 import { UserRound } from 'lucide-react';
 import React from 'react';
@@ -56,15 +56,16 @@ const Header = ({ title, avatar = { isVisible: false }, CenterComponent, LeftCom
         <Title>{title}</Title>
       </LeftSection>
       {CenterComponent && <CenterSection>{CenterComponent}</CenterSection>}
-      <RightSection>{RightComponent}</RightSection>
+      <RightSection hasCenter={!!CenterComponent}>{RightComponent}</RightSection>
     </Container>
   );
 };
 
 const Title = styled.div`
   color: white;
-  flex: 1 0 auto;
   font-size: 24px;
+  word-break: break-word;
+  overflow-wrap: break-word;
 `;
 
 const LeftSection = styled.div`
@@ -82,10 +83,10 @@ const CenterSection = styled.div`
   white-space: nowrap;
 `;
 
-const RightSection = styled.div`
-  flex: 1;
+const RightSection = styled.div<{ hasCenter: boolean }>`
   display: flex;
   justify-content: flex-end;
+  ${(props) => props.hasCenter && `flex: 1;`}
 `;
 
 const Container = styled.div`
diff --git a/app/koi-client/src/component-presentation/InfoBox.tsx b/app/koi-client/src/component-presentation/InfoBox.tsx
index 7ed2cfec..e2a59e8d 100644
--- a/app/koi-client/src/component-presentation/InfoBox.tsx
+++ b/app/koi-client/src/component-presentation/InfoBox.tsx
@@ -1,5 +1,5 @@
-import React, { CSSProperties } from 'react';
-import { styled } from '@linaria/react';
+import styled from '@emotion/styled';
+import { CSSProperties } from 'react';
 
 interface InfoBoxProps {
   title?: string;
@@ -9,7 +9,7 @@ interface InfoBoxProps {
   changeTime?: React.ReactNode;
 }
 
-const InfoBox: React.FC<InfoBoxProps> = ({ title, value, valueColor, leftTime, changeTime }) => {
+const InfoBox = ({ title, value, valueColor, leftTime, changeTime }: InfoBoxProps) => {
   return (
     <Container>
       <Wrapper>
@@ -48,8 +48,9 @@ const Wrapper = styled.div`
 const TimeWrapper = styled.div`
   display: flex;
   flex-direction: column;
+  row-gap: 4px;
   background-color: #374151;
-  padding: 12px 4px;
+  padding: 10px 8px;
   border-radius: 4px;
   text-align: center;
 `;
@@ -62,8 +63,7 @@ const ContainerTitle = styled.div`
 
 const ContainerBolder = styled.div`
   font-size: 20px;
-  font-weight: bolder;
-  line-height: 22px;
+  font-weight: 400;
   display: flex;
   align-items: center;
   letter-spacing: 0.5px;
diff --git a/app/koi-client/src/page/@/component/PartyList.tsx b/app/koi-client/src/page/@/component/PartyList.tsx
index f9bdcb4b..838fc077 100644
--- a/app/koi-client/src/page/@/component/PartyList.tsx
+++ b/app/koi-client/src/page/@/component/PartyList.tsx
@@ -1,7 +1,7 @@
 import { useAtomValue } from 'jotai';
 import { useNavigate } from 'react-router-dom';
-import { Gamepad2, Users } from 'lucide-react';
 import styled from '@emotion/styled';
+import { Gamepad2, Users } from 'lucide-react';
 import { UserStore } from '../../../store';
 import { Query } from '../../../hook';
 
@@ -17,44 +17,67 @@ const PartyList = () => {
     return <></>;
   }
 
-  return partyList.map((party) => {
-    return (
-      party.activityId !== 'CLOSE' && (
-        <PartyCard key={party._id}>
-          <PartyInformation>
-            <PartyTitle>{party.title}</PartyTitle>
-            <ParticipantCount>
-              <Users style={{ height: '16px', width: '16px' }} />
-              {party.joinedUserIds.length}/{party.limitAllCount}
-            </ParticipantCount>
-          </PartyInformation>
-          <ParticipateButton
-            data-id={party._id}
-            onClick={async () => {
-              await joinParty({ partyId: party._id, userId: supabaseSession.user.id });
-              navigate(`/party/${party._id}`);
-            }}
-            // disabled={party.publicScope !== 'PUBLIC'}
-          >
-            참가하기
-            <Gamepad2 />
-          </ParticipateButton>
-        </PartyCard>
-      )
-    );
-  });
+  return (
+    <>
+      <H2>🎮 게임 리스트</H2>
+      {partyList?.map((party) => {
+        return (
+          party.activityId !== 'CLOSE' && (
+            <PartyCard key={party._id}>
+              <PartyInformation>
+                <PartyTitle>{party.title}</PartyTitle>
+                <ParticipantCount>
+                  <Users style={{ height: '16px', width: '16px' }} />
+                  {party.joinedUserIds.length}/{party.limitAllCount}
+                </ParticipantCount>
+              </PartyInformation>
+              <ParticipateButton
+                data-id={party._id}
+                onClick={async () => {
+                  await joinParty({ partyId: party._id, userId: supabaseSession.user.id });
+                  navigate(`/party/${party._id}`);
+                }}
+                // disabled={party.publicScope !== 'PUBLIC'}
+              >
+                참가하기
+                <Gamepad2 />
+              </ParticipateButton>
+            </PartyCard>
+          )
+        );
+      })}
+    </>
+  );
 };
 
 export default PartyList;
 
+const H2 = styled.h2`
+  position: relative;
+  font-size: 18px;
+  font-weight: 400;
+  color: white;
+  margin: 0 0 12px 0;
+  display: flex;
+  align-items: center;
+
+  &::after {
+    content: '';
+    flex: 1;
+    height: 1px;
+    background-color: #374151;
+    margin-left: 12px;
+  }
+`;
+
 const PartyCard = styled.div`
   display: flex;
   align-items: center;
   justify-content: space-between;
 
-  background-color: #252836;
-  padding: 20px 24px;
-  border-radius: 4px;
+  background-color: #1a1e2d;
+  padding: 20px 16px 20px 24px;
+  border-radius: 12px;
 `;
 const PartyInformation = styled.div`
   display: flex;
@@ -62,34 +85,38 @@ const PartyInformation = styled.div`
   justify-content: center;
   row-gap: 12px;
   overflow: hidden;
+  flex: 1;
+  min-width: 0;
 `;
 const PartyTitle = styled.h2`
   color: white;
   font-size: 20px;
-  margin: 0;
-  word-wrap: break-word;
+  font-weight: 400;
+  word-break: break-word;
   overflow-wrap: break-word;
-  white-space: normal;
 `;
 const ParticipantCount = styled.div`
   display: flex;
   align-items: center;
   column-gap: 4px;
-  font-size: 20px;
+  font-size: 14px;
   color: rgba(255, 255, 255, 0.6);
 `;
 
 const ParticipateButton = styled.button`
-  flex-shrink: 0;
-  font-family: DungGeunMo;
   display: flex;
   align-items: center;
   column-gap: 8px;
-  padding: 8px;
-  background-color: transparent;
+
+  flex-shrink: 0;
+  border: none;
   border-radius: 4px;
-  border: 1px solid #b6c3fd;
-  color: #b6c3fd;
+  font-family: DungGeunMo;
+
+  padding: 4px 12px;
+  margin-left: 12px;
+  background-color: #2d3244;
+  color: #ffffff;
   font-size: 14px;
   cursor: pointer;
 `;
diff --git a/app/koi-client/src/page/@party@[partyId]/component/MainHeader.tsx b/app/koi-client/src/page/@party@[partyId]/component/MainHeader.tsx
index 7a7696d2..9122ead3 100644
--- a/app/koi-client/src/page/@party@[partyId]/component/MainHeader.tsx
+++ b/app/koi-client/src/page/@party@[partyId]/component/MainHeader.tsx
@@ -56,7 +56,7 @@ const PartyHeader = () => {
             }}
             className={css`
               color: white;
-              font-size: 32px;
+              flex-shrink: 0;
               &:hover {
                 cursor: pointer;
               }
diff --git a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/DrawInfo.tsx b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/DrawInfo.tsx
index 41fab7d8..89edb59d 100644
--- a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/DrawInfo.tsx
+++ b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/DrawInfo.tsx
@@ -19,7 +19,7 @@ const DrawStockInfo = ({ stockId }: Props) => {
   const { allSellPrice } = Query.Stock.useAllSellPrice({ stockId, userId });
 
   const [open, setOpen] = useState(false);
-  const modalRef = useRef<HTMLDivElement>(null);
+  const modalRef = useRef<HTMLUListElement>(null);
   const [messageApi, contextHolder] = message.useMessage();
   const { data: stock, timeIdx } = Query.Stock.useQueryStock(stockId);
 
@@ -64,9 +64,9 @@ const DrawStockInfo = ({ stockId }: Props) => {
   return (
     <>
       {contextHolder}
-      <InformationDrawButton onClick={() => setOpen(true)} disabled={isDisabled}>
+      <InfoExtractButton onClick={() => setOpen(true)} disabled={isDisabled}>
         정보 뽑기
-      </InformationDrawButton>
+      </InfoExtractButton>
       <div
         css={{
           position: 'absolute',
@@ -75,24 +75,51 @@ const DrawStockInfo = ({ stockId }: Props) => {
         <Modal
           title="주식 정보 뽑기"
           open={open}
+          centered
           onCancel={() => setOpen(false)}
           okText="뽑기"
           cancelText="닫기"
           getContainer={false}
-          okButtonProps={{ loading: isLoading }}
+          okButtonProps={{ loading: isLoading, style: { backgroundColor: COLOR.green } }}
+          cancelButtonProps={{ style: { backgroundColor: '#252836', color: 'white' } }}
           onOk={onClickDrawStockInfo}
         >
-          <div ref={modalRef} tabIndex={-1}>
-            <p>1회 뽑는 데 30만원의 금액이 필요해요.</p>
-            <p>수익률 0% 이상일 때만 뽑기를 할 수 있어요.</p>
-          </div>
+          <InfoExtractionRulesList ref={modalRef} tabIndex={-1}>
+            <li>
+              <h3>1. 정보 뽑기 비용</h3>
+              <p>
+                1회 뽑는 데 <HighlightedText>30만원</HighlightedText>의 금액이 필요해요.
+              </p>
+            </li>
+            <li>
+              <h3>2. 정보 뽑기 조건</h3>
+              <p>
+                <HighlightedText>수익률 0% 이상</HighlightedText>일 때만 뽑기를 할 수 있어요.
+              </p>
+            </li>
+          </InfoExtractionRulesList>
         </Modal>
       </div>
     </>
   );
 };
 
-const InformationDrawButton = styled.button`
+const InfoExtractionRulesList = styled.ul`
+  list-style: none;
+  font-size: 12px;
+  color: #9ca3af;
+  padding: 3px 0;
+
+  & > li > h3 {
+    font-size: 15px;
+    color: rgba(255, 255, 255, 0.8);
+  }
+`;
+const HighlightedText = styled.span`
+  color: ${COLOR.pastelGreen};
+`;
+
+const InfoExtractButton = styled.button`
   width: 100%;
   font-family: 'DungGeunMo';
   padding: 16px;
diff --git a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Home/Home.tsx b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Home/Home.tsx
index c44b7158..aa792aaf 100644
--- a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Home/Home.tsx
+++ b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Home/Home.tsx
@@ -76,7 +76,7 @@ const Home = ({ stockId }: Props) => {
   }, [stock?.startedTime, refetch]);
 
   if (!user || !stock) {
-    return <div>불러오는 중.</div>;
+    return <div>불러오는 중..</div>;
   }
 
   const gameTimeInSeconds = parseInt(gameTime.split(':')[0], 10) * 60 + parseInt(gameTime.split(':')[1], 10);
@@ -218,7 +218,12 @@ const Home = ({ stockId }: Props) => {
         </FutureInfoWrapper>
       </Wrapper>
       <StickyBottom>
-        <StartLoan stockId={stockId} />
+        <StartLoan
+          stockId={stockId}
+          money={user.money}
+          loanCount={user.loanCount}
+          allSellPrice={commaizeNumber(allSellPrice)}
+        />
       </StickyBottom>
     </>
   );
@@ -253,6 +258,7 @@ const LeftSection = styled.div`
 const H3 = styled.h3`
   font-size: 16px;
   margin: 0;
+  font-weight: 400;
 `;
 
 const H5 = styled.h5`
@@ -261,16 +267,20 @@ const H5 = styled.h5`
   margin: 0;
   padding: 8px 8px;
   cursor: pointer;
+  font-weight: 400;
 `;
 
 const H4 = styled.h4`
   font-size: 10px;
+  color: #d4d4d8;
+  font-weight: 400;
 `;
 
 const H6 = styled.h6`
   font-size: 12px;
   margin: 0;
   color: #c084fc;
+  font-weight: 400;
 `;
 
 const H6Wrapper = styled.div`
diff --git a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Home/MyLevel.tsx b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Home/MyLevel.tsx
index 6549ab00..1bf53da4 100644
--- a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Home/MyLevel.tsx
+++ b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Home/MyLevel.tsx
@@ -174,9 +174,6 @@ const NextLevel = styled.div`
   color: #a1a1aa;
   flex: auto;
   white-space: nowrap;
-  span {
-    font-weight: 600;
-  }
 `;
 
 const PercentValue = styled.div`
diff --git a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Information.tsx b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Information.tsx
index 8e4daf09..b434a5ff 100644
--- a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Information.tsx
+++ b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/Information.tsx
@@ -123,7 +123,7 @@ const Information = ({ stockId }: Props) => {
                   letter-spacing: 0.5px;
                 `}
               >
-                {remainingTime <= 1 ? `🚨 임박` : `${remainingTime}분 후`}
+                {remainingTime <= 1 ? <span style={{ color: '#f96257' }}>🚨 임박</span> : `${remainingTime}분 후`}
               </div>
             }
             changeTime={
@@ -196,6 +196,7 @@ const Container = styled.div`
   display: flex;
   flex-direction: column;
   gap: 12px;
+  padding-bottom: 100px;
 `;
 
 const TitleWrapper = styled.div`
diff --git a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/RecommendedPartnersModal.tsx b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/RecommendedPartnersModal.tsx
index 680b0f44..7c77953c 100644
--- a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/RecommendedPartnersModal.tsx
+++ b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/RecommendedPartnersModal.tsx
@@ -1,7 +1,8 @@
-import { Modal } from 'antd';
+import { Avatar, Modal } from 'antd';
 import { ReactElement, cloneElement, useReducer } from 'react';
 import styled from '@emotion/styled';
 import { useRecommendedPartners } from '../../../../../../hook/query/Stock/useRecommendedPartners';
+import * as COLOR from '../../../../../../config/color';
 
 interface ButtonProps {
   onClick?: () => void;
@@ -27,12 +28,22 @@ const RecommendedPartnersModal = ({ trigger, stockId }: Props) => {
         centered
         footer={null}
       >
-        <p>흥미로운 대화 상대를 발견했어요 ✨</p>
-        <PartnerList>
-          {partnerNicknames.map((name) => (
-            <li key={name}>{name}</li>
-          ))}
-        </PartnerList>
+        <PartnerDescription>
+          일부 <span>정보를 공유</span>하는 대화 상대를 발견했어요 👀
+        </PartnerDescription>
+
+        {partnerNicknames?.length === 0 ? (
+          <PartnerDescription>라고 할 뻔.. 사실 발견 못했어요 😢</PartnerDescription>
+        ) : (
+          <PartnerList>
+            {partnerNicknames.map((name) => (
+              <PartnerItem key={name}>
+                <Avatar size={40}>{name?.[0]}</Avatar>
+                <span>{name}</span>
+              </PartnerItem>
+            ))}
+          </PartnerList>
+        )}
       </Modal>
     </>
   );
@@ -40,12 +51,29 @@ const RecommendedPartnersModal = ({ trigger, stockId }: Props) => {
 
 export default RecommendedPartnersModal;
 
-const PartnerList = styled.ul`
-  list-style-type: disc;
-  padding-left: 20px;
-  font-size: 16px;
+const PartnerDescription = styled.p`
+  font-size: 12px;
+  color: #9ca3af;
 
-  li {
-    margin: 8px 0;
+  & > span {
+    color: ${COLOR.pastelGreen};
   }
 `;
+
+const PartnerList = styled.ul`
+  display: flex;
+  flex-direction: column;
+  row-gap: 16px;
+  color: rgb(213, 213, 213);
+  padding-left: 0px;
+  font-size: 17px;
+`;
+
+const PartnerItem = styled.li`
+  background-color: #2a2d3a;
+  border-radius: 6px;
+  padding: 8px;
+  display: flex;
+  align-items: center;
+  column-gap: 16px;
+`;
diff --git a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/StartLoan.tsx b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/StartLoan.tsx
index 64939f84..cdef8447 100644
--- a/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/StartLoan.tsx
+++ b/app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/StartLoan.tsx
@@ -8,16 +8,19 @@ import * as COLOR from '../../../../../../config/color';
 
 type Props = {
   stockId: string;
+  loanCount: number;
+  money: number;
+  allSellPrice: string;
 };
 
-const StartLoan = ({ stockId }: Props) => {
+const StartLoan = ({ stockId, loanCount, money, allSellPrice }: Props) => {
   const supabaseSession = useAtomValue(UserStore.supabaseSession);
   const userId = supabaseSession?.user.id;
 
   const { mutateAsync: startLoan, isLoading } = Query.Stock.useStartLoan();
 
   const [open, setOpen] = useState(false);
-  const modalRef = useRef<HTMLDivElement>(null);
+  const modalRef = useRef<HTMLUListElement>(null);
   const [messageApi, contextHolder] = message.useMessage();
   const { data: stock, timeIdx } = Query.Stock.useQueryStock(stockId);
 
@@ -58,6 +61,55 @@ const StartLoan = ({ stockId }: Props) => {
 
   const isDisabled = timeIdx === undefined || !stock.isTransaction;
 
+  // 매수 가능 금액과 주식 가치 계산
+  const availableMoney = money;
+  const stockValue = parseInt(allSellPrice, 10) || 0;
+  const totalAssets = availableMoney + stockValue;
+
+  // 대출 가능 여부 메시지 생성
+  const getLoanStatusInfo = () => {
+    if (availableMoney >= 1000000) {
+      return {
+        message: `현재 매수 가능 금액이 ${availableMoney.toLocaleString()}원으로, 이미 100만원 이상입니다.`,
+        status: '대출 불가능',
+        statusColor: '#c22e08',
+      };
+    }
+    if (totalAssets >= 1000000) {
+      return {
+        message: `매수 가능 금액(${availableMoney.toLocaleString()}원)과 주식가치(${stockValue.toLocaleString()}원)의 합이 ${totalAssets.toLocaleString()}원으로, 100만원을 초과합니다.`,
+        status: '대출 불가능',
+        statusColor: '#c22e08',
+      };
+    }
+    return {
+      message: `매수 가능 금액(${availableMoney.toLocaleString()}원)과 주식가치(${stockValue.toLocaleString()}원)의 합이 ${totalAssets.toLocaleString()}원으로, 100만원 미만입니다.`,
+      status: '대출 가능',
+      statusColor: '#166f35',
+    };
+  };
+
+  // 상환 정보 생성
+  const getRepaymentInfo = () => {
+    if (loanCount === 0) {
+      return {
+        message: '지금까지 대출을 받지 않아 게임 종료 시 회수할 금액이 없습니다.',
+        status: '상환 없음',
+        statusColor: '#166f35',
+      };
+    }
+    return {
+      // 노란색으로 경고
+      message: `지금까지 대출을 ${loanCount}번 받아 게임 종료 시 ${loanCount * 200}만원을 회수할 예정입니다.`,
+
+      status: `${loanCount * 200}만원 상환 예정`,
+      statusColor: '#7c5e11',
+    };
+  };
+
+  const loanStatus = getLoanStatusInfo();
+  const repaymentInfo = getRepaymentInfo();
+
   return (
     <>
       {contextHolder}
@@ -69,27 +121,233 @@ const StartLoan = ({ stockId }: Props) => {
           position: 'absolute',
         }}
       >
-        <Modal
+        <StyledModal
           title="대출하기"
           open={open}
+          centered
           onCancel={() => setOpen(false)}
           okText="대출하기"
           cancelText="닫기"
           getContainer={false}
-          okButtonProps={{ loading: isLoading }}
+          cancelButtonProps={{ style: { backgroundColor: '#252836', color: 'white' } }}
+          okButtonProps={{
+            loading: isLoading,
+            style: { backgroundColor: COLOR.violetLight },
+          }}
           onOk={onClickStartLoan}
         >
-          <div ref={modalRef} tabIndex={-1}>
-            <p>1회 대출시 100만원을 받을 수 있어요</p>
-            <p>[매수 가능 금액]이나 [매수 가능 금액 + 주식가치]의 합이 100만원 이상일 경우 대출을 받을 수 없어요</p>
-            <p>게임이 종료되면 [대출 횟수 * 200만원]만큼 회수를 해요</p>
-          </div>
-        </Modal>
+          <ScrollContainer>
+            <LoanRulesList ref={modalRef} tabIndex={-1}>
+              <li>
+                <RuleTitle>1. 대출 금액</RuleTitle>
+                <RuleDescription>
+                  1회 대출시 <HighlightedText>100만원</HighlightedText>을 받을 수 있어요
+                </RuleDescription>
+                <StatusCard>
+                  <InfoRow>
+                    <InfoLabel>현재 금액</InfoLabel>
+                    <InfoValue>{availableMoney.toLocaleString()}원</InfoValue>
+                  </InfoRow>
+                  <InfoRow>
+                    <InfoLabel>대출 후 금액</InfoLabel>
+                    <InfoValue color="#4caf50" highlight>
+                      {(availableMoney + 1000000).toLocaleString()}원
+                    </InfoValue>
+                  </InfoRow>
+                </StatusCard>
+              </li>
+              <li>
+                <RuleTitle>2. 대출 가능 조건</RuleTitle>
+                <RuleDescription>
+                  [매수 가능 금액]이나 [매수 가능 금액 + 주식가치]의 <HighlightedText>합</HighlightedText>이 100만원
+                  이상일 경우 대출을 받을 수 없어요
+                </RuleDescription>
+                <StatusCard>
+                  <StatusHeader>
+                    <StatusBadge color={loanStatus.statusColor}>{loanStatus.status}</StatusBadge>
+                    <StatusMessage color={loanStatus.statusColor === '#166f35' ? '#a3e9b4' : '#ffb8a8'}>
+                      {loanStatus.message}
+                    </StatusMessage>
+                  </StatusHeader>
+                  <InfoTable>
+                    <InfoRow>
+                      <InfoLabel>매수 가능 금액</InfoLabel>
+                      <InfoValue>{availableMoney.toLocaleString()}원</InfoValue>
+                    </InfoRow>
+                    <InfoRow>
+                      <InfoLabel>주식가치</InfoLabel>
+                      <InfoValue>{stockValue.toLocaleString()}원</InfoValue>
+                    </InfoRow>
+                    <InfoRow>
+                      <InfoLabel>합계</InfoLabel>
+                      <InfoValue color={totalAssets >= 1000000 ? '#ff6347' : '#4caf50'}>
+                        {totalAssets.toLocaleString()}원
+                      </InfoValue>
+                    </InfoRow>
+                  </InfoTable>
+                </StatusCard>
+              </li>
+              <li>
+                <RuleTitle>3. 상환 조건</RuleTitle>
+                <RuleDescription>
+                  게임이 종료되면 <HighlightedText>[대출 횟수 * 200만원]</HighlightedText> 만큼 회수를 해요
+                </RuleDescription>
+                <StatusCard>
+                  <StatusHeader>
+                    <StatusBadge color={repaymentInfo.statusColor}>{repaymentInfo.status}</StatusBadge>
+                    <StatusMessage color={repaymentInfo.statusColor === '#166f35' ? '#a3e9b4' : '#ffe0a3'}>
+                      {repaymentInfo.message}
+                    </StatusMessage>
+                  </StatusHeader>
+                  <InfoTable>
+                    <InfoRow>
+                      <InfoLabel>대출 횟수</InfoLabel>
+                      <InfoValue>{loanCount}회</InfoValue>
+                    </InfoRow>
+                    {loanCount > 0 && (
+                      <InfoRow>
+                        <InfoLabel>예상 상환 금액</InfoLabel>
+                        <InfoValue color="#ff6347">{(loanCount * 200).toLocaleString()}만원</InfoValue>
+                      </InfoRow>
+                    )}
+                  </InfoTable>
+                </StatusCard>
+              </li>
+            </LoanRulesList>
+          </ScrollContainer>
+        </StyledModal>
       </div>
     </>
   );
 };
 
+// 스타일된 모달 컴포넌트
+const StyledModal = styled(Modal)`
+  .ant-modal-body {
+    height: 70dvh;
+  }
+`;
+
+// 스크롤 가능한 컨테이너
+const ScrollContainer = styled.div`
+  height: 100%;
+  overflow-y: auto;
+  padding-right: 8px;
+
+  /* 스크롤바 스타일링 */
+  &::-webkit-scrollbar {
+    width: 4px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: #1f2028;
+    border-radius: 4px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #3a3e4c;
+    border-radius: 4px;
+  }
+
+  &::-webkit-scrollbar-thumb:hover {
+    background: #4d5060;
+  }
+`;
+
+const LoanRulesList = styled.ul`
+  list-style: none;
+  font-size: 12px;
+  padding: 3px 0;
+  margin: 0;
+
+  & > li {
+    margin-bottom: 20px;
+  }
+
+  & > li:last-child {
+    margin-bottom: 4px;
+  }
+`;
+
+const RuleTitle = styled.h3`
+  font-size: 15px;
+  color: rgba(255, 255, 255, 0.9);
+  margin-bottom: 6px;
+  font-weight: 600;
+`;
+
+const RuleDescription = styled.p`
+  color: rgba(255, 255, 255, 0.7);
+  font-size: 12px;
+  margin-bottom: 10px;
+`;
+
+const HighlightedText = styled.span`
+  color: ${COLOR.pastelGreen};
+  font-weight: 600;
+`;
+
+const StatusCard = styled.div`
+  background-color: #2a2d3a;
+  border-radius: 8px;
+  padding: 12px;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+`;
+
+const StatusHeader = styled.div`
+  display: flex;
+  align-items: flex-start;
+  gap: 10px;
+  margin-bottom: 2px;
+`;
+
+const StatusMessage = styled.p<{ color: string }>`
+  margin: 0;
+  font-size: 10px;
+  color: ${(props) => props.color};
+  flex: 1;
+  line-height: 1.5;
+`;
+
+const InfoTable = styled.div`
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  border-top: 1px solid #3a3e4c;
+  padding-top: 10px;
+  margin-top: 2px;
+`;
+
+const InfoRow = styled.div`
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+`;
+
+const InfoLabel = styled.span`
+  color: #9ca3af;
+  font-size: 11px;
+`;
+
+const InfoValue = styled.span<{ highlight?: boolean; color?: string }>`
+  font-size: 12px;
+  font-weight: ${(props) => (props.highlight ? 'bold' : 'normal')};
+  color: ${(props) => (props.color ? props.color : props.highlight ? COLOR.pastelGreen : 'white')};
+`;
+
+const StatusBadge = styled.div<{ color: string }>`
+  background-color: ${(props) => props.color};
+  color: white;
+  padding: 4px 8px;
+  border-radius: 4px;
+  font-size: 10px;
+  font-weight: bold;
+  display: inline-block;
+  white-space: nowrap;
+`;
+
 const LoanButton = styled.button`
   width: 100%;
   font-family: 'DungGeunMo';
diff --git a/app/koi-client/src/page/@profile/component/ProfileHeader.tsx b/app/koi-client/src/page/@profile/component/ProfileHeader.tsx
index c8ec278d..8d320931 100644
--- a/app/koi-client/src/page/@profile/component/ProfileHeader.tsx
+++ b/app/koi-client/src/page/@profile/component/ProfileHeader.tsx
@@ -16,6 +16,8 @@ const ProfileHeader = () => {
             navigate(-1);
           }}
           className={css`
+            color: white;
+            flex-shrink: 0;
             &:hover {
               cursor: pointer;
             }


Reviews:
user: login: omizha
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-08T17:05:58Z
user: login: JANGSEYEONG
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-08T18:26:37Z
user: login: jhlee0409
body: 수고하셨습니다 👍👍👍👍
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-08T18:28:53Z

Review comments:
diff_hunk: @@ -72,24 +72,60 @@ const StartLoan = ({ stockId }: Props) => {
         <Modal
           title="대출하기"
           open={open}
+          centered
           onCancel={() => setOpen(false)}
           okText="대출하기"
           cancelText="닫기"
           getContainer={false}
-          okButtonProps={{ loading: isLoading }}
+          cancelButtonProps={{ style: { backgroundColor: '#252836', color: 'white' } }}
+          okButtonProps={{
+            loading: isLoading,
+            style: { backgroundColor: COLOR.violetLight },
+          }}
           onOk={onClickStartLoan}
         >
-          <div ref={modalRef} tabIndex={-1}>
-            <p>1회 대출시 100만원을 받을 수 있어요</p>
-            <p>[매수 가능 금액]이나 [매수 가능 금액 + 주식가치]의 합이 100만원 이상일 경우 대출을 받을 수 없어요</p>
-            <p>게임이 종료되면 [대출 횟수 * 200만원]만큼 회수를 해요</p>
-          </div>
+          <LoanRulesList ref={modalRef} tabIndex={-1}>
+            <li>
+              <h3>1. 대출 금액</h3>
+              <p>
+                1회 대출시 <HighlightedText>100만원</HighlightedText>을 받을 수 있어요
+              </p>
+            </li>
+            <li>
+              <h3>2. 대출 가능 조건</h3>
+              <p>
+                [매수 가능 금액]이나 [매수 가능 금액 + 주식가치]의 <HighlightedText>합</HighlightedText>이 100만원
path: app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/StartLoan.tsx
user: login: omizha
body: 텍스트가 너무 어려운데, example 설명을 따로 넣었으면 좋겠어요 (매수 가능 금액 + 주식가치 현재 금액을 보여주면서 설명한다던지 => 현재 929,000원이 있어서 대출을 받을 수 있어요!)

상환 조건도 마찬가지 (ex. 지금까지 대출을 받지 않아 회수를 하지 않을 예정이예요 or 1번 대출했기 때문에 200만원 회수할 예정이예요)

사담) 토스가 금융을 얼마나 쉽게 하는지 알게되는 순간...
created_at: 2025-03-08T17:05:58Z
author_association: COLLABORATOR
diff_hunk: @@ -72,24 +72,60 @@ const StartLoan = ({ stockId }: Props) => {
         <Modal
           title="대출하기"
           open={open}
+          centered
           onCancel={() => setOpen(false)}
           okText="대출하기"
           cancelText="닫기"
           getContainer={false}
-          okButtonProps={{ loading: isLoading }}
+          cancelButtonProps={{ style: { backgroundColor: '#252836', color: 'white' } }}
+          okButtonProps={{
+            loading: isLoading,
+            style: { backgroundColor: COLOR.violetLight },
+          }}
           onOk={onClickStartLoan}
         >
-          <div ref={modalRef} tabIndex={-1}>
-            <p>1회 대출시 100만원을 받을 수 있어요</p>
-            <p>[매수 가능 금액]이나 [매수 가능 금액 + 주식가치]의 합이 100만원 이상일 경우 대출을 받을 수 없어요</p>
-            <p>게임이 종료되면 [대출 횟수 * 200만원]만큼 회수를 해요</p>
-          </div>
+          <LoanRulesList ref={modalRef} tabIndex={-1}>
+            <li>
+              <h3>1. 대출 금액</h3>
+              <p>
+                1회 대출시 <HighlightedText>100만원</HighlightedText>을 받을 수 있어요
+              </p>
+            </li>
+            <li>
+              <h3>2. 대출 가능 조건</h3>
+              <p>
+                [매수 가능 금액]이나 [매수 가능 금액 + 주식가치]의 <HighlightedText>합</HighlightedText>이 100만원
path: app/koi-client/src/page/@party@[partyId]/component/Stock/component/Stock/StartLoan.tsx
user: login: JANGSEYEONG
body: # 대출 기능 UI 개선

- 사용자의 현재 금융 상태에 맞는 대출 가능/불가능 상태 시각화
- 상태별 컬러 표시 (초록색: 대출 가능, 빨간색: 대출 불가, 노란색: 경고)
- 직관적인 상태 메시지로 사용자 이해도 향상
- 스크롤바 스타일링 개선 및 다양한 화면 높이(512px 이상)에서도 정상 작동 확인

|대출 가능 + 상환 없음|대출 불가 + 상환 있음|512px 높이 기준 스크롤 생성 확인|
|---|---|---|
|<img width="276" alt="image" src="https://github.com/user-attachments/assets/5c0fabe5-4b72-4160-9b72-7e2d2017622b" />|<img width="253" alt="image" src="https://github.com/user-attachments/assets/0d8a6679-d6ae-4f7a-ba18-93d09e178fe7" />|<img width="316" alt="image" src="https://github.com/user-attachments/assets/b8a00a18-9e56-4eac-8458-26004a7d04cb" />|





created_at: 2025-03-08T18:26:37Z
author_association: CONTRIBUTOR

PR comments:
user: login: codeeon
created_at: 2025-03-08T19:06:46Z
body: 개선 후를 봐버렸네요. 너무 예쁨...!
고생하셨습니다!! 👍👍👍 다재다능 루나 만세!!

author_association: CONTRIBUTOR
user: login: JANGSEYEONG
created_at: 2025-03-08T20:53:56Z
body: ## 파티 리스트 카드 타이틀

- UI 개선 ([43eaba8](https://github.com/omizha/sdc-stock/pull/35/commits/43eaba8e453a053ee2caf2966f67072d444bba31))
- 화면 너비 좁을 때 ( [1902f06](https://github.com/omizha/sdc-stock/pull/35/commits/1902f06f89b5bb655d8ca623338572246c65b789) )
  - 파티 방 이름 줄바꿈 처리
  - 버튼과 파티 방 이름 간격 처리

https://github.com/user-attachments/assets/5065c6f3-569c-4d3d-8da4-d492986ae42d


## 게임 내 헤더 타이틀


- 화면 너비 좁을 때 ([de0f480](https://github.com/omizha/sdc-stock/pull/35/commits/de0f48051782b0871e85138db364729cd0438d76))
  - 게임 타이틀 줄바꿈 처리 추가
  - CenterComponent가 있는 경우에만 RightCompinent에 `flex:1` 추가 (중앙 자리 위치 잡기를 위해서!!!)

https://github.com/user-attachments/assets/d425d53f-3176-46d6-a9ea-95f6a46530d5






author_association: CONTRIBUTOR
user: login: omizha
created_at: 2025-03-09T13:28:58Z
body: 와 짱짱 루나.. 진짜 디자인이 예쁘게 바뀌었어요!! ✨✨
바로 머지하겠슴다
author_association: COLLABORATOR