designpaca/apps/site/public/work/saebyeok-cheonggwa/index.html
Yun Chan 8e3cdb0d3b
Some checks are pending
ci / build (push) Waiting to run
feat(site): rework 19 marketing showcases for composition diversity
Measured convergence before: split hero 13/19, top-bar nav 19/19,
one-line notice footer 14/19, body Pretendard 17/21, 10 similarity
pairs above 0.78. Each showcase got a pre-assigned hero family, nav
form, footer form, type pair, background, accent hue, radius, motion
grammar and material from outputs/rework-2026-10-06/plan.md; direction
cards and the chosen reason are recorded in every design.md.

After: 0 similarity warnings, 19 distinct display faces, 7 hero
families, 5 nav forms, 5 footer forms, no scroll reveals, 5 showcases
with SVG filter materials. Example contact values replace bracket
placeholders under the existing fictional-brand notices. Thumbnails,
OG images, card copy and three e2e assertions updated; dead CSS in
dure-enrollment and hannam-jari removed; similarity.mjs learns the new
font families.
2026-10-06 16:55:50 +09:00

989 lines
47 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>새벽청과 — 오늘 새벽 경매 낙찰가</title>
<meta
name="description"
content="새벽 경매에서 낙찰받아 그날 아침에 보냅니다. 품목마다 산지, 등급, 당도, 규격과 오늘 낙찰가를 그대로 적는 청과 직거래."
/>
<meta property="og:title" content="새벽청과" />
<meta property="og:description" content="새벽 경매에서 받은 과일의 산지, 등급, 당도와 오늘 낙찰가를 공개하고 그날 아침 보내 드립니다." />
<meta property="og:type" content="website" />
<meta property="og:image" content="./og.png" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="theme-color" content="#e4e8f4" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Gasoek+One&family=Noto+Sans+KR:wght@400;500;700&display=swap"
/>
<link rel="stylesheet" href="./styles/tokens.css?v=20261006" />
<link rel="stylesheet" href="./styles/main.css?v=20261006" />
<link
rel="icon"
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='4' fill='%23e4e8f4'/%3E%3Cpath d='M6 21h20' stroke='%2322673a' stroke-width='3'/%3E%3Ccircle cx='13' cy='13' r='4.5' fill='none' stroke='%23141a2b' stroke-width='2.5'/%3E%3C/svg%3E"
/>
</head>
<body>
<a class="skip-link" href="#main">본문으로 건너뛰기</a>
<header class="site-head">
<div class="wrap head-inner">
<a class="wordmark" href="#top">새벽청과</a>
<p class="hero-meta">
<time datetime="2026-10-06T02:00+09:00">10월 06일 02:00</time>
<span>경매 기준</span>
</p>
</div>
</header>
<main id="main">
<!-- 1 · 시세표가 첫 화면이다. 표제는 작고, 낙찰가 숫자가 가장 크다 -->
<section class="board-section" id="top" aria-labelledby="heroHeading">
<div class="wrap">
<div class="board-head">
<h1 id="heroHeading">오늘 새벽 경매 낙찰가</h1>
<p class="board-lead">
사과와 배는 08:30, 나머지 네 품목은 02:00 경매에서 받은 값입니다. 낙찰가에
선별, 포장, 배송비가 더해져 판매가가 되고, 두 가격은 따로 적습니다.
</p>
</div>
<div class="tabs" role="tablist" aria-label="시세 보기">
<button
class="tab"
type="button"
role="tab"
id="tabItems"
aria-selected="true"
aria-controls="panelItems"
>품목별 시세</button>
<button
class="tab"
type="button"
role="tab"
id="tabDates"
aria-selected="false"
aria-controls="panelDates"
tabindex="-1"
>일자별 변동</button>
</div>
<div class="panel" id="panelItems" role="tabpanel" aria-labelledby="tabItems">
<div class="board-scroll">
<table class="board">
<caption class="sr-only">
오늘 낙찰 품목 여섯 가지. 산지, 등급, 당도, 규격, 낙찰가, 전일 대비
</caption>
<thead>
<tr>
<th scope="col" class="col-name">품목</th>
<th scope="col" class="col-origin">산지</th>
<th scope="col" class="c-num col-grade">등급</th>
<th scope="col" class="c-num col-brix">당도</th>
<th scope="col" class="c-num col-pack">규격</th>
<th scope="col" class="c-num col-price">낙찰가</th>
<th scope="col" class="c-num col-delta">전일 대비</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" class="col-name">
<button
class="board-select"
type="button"
data-market-row
data-name="백도 복숭아"
data-origin="경북 청도"
data-grade="특 등급, 12.5 Bx"
data-pack="4.5 kg"
data-price="38,000원"
data-delta="▲ 2,000원"
data-auction="02:00 경매"
aria-pressed="true"
>백도 복숭아</button>
</th>
<td class="col-origin">경북 청도</td>
<td class="c-num col-grade">특</td>
<td class="c-num col-brix">12.5<span class="unit">Bx</span></td>
<td class="c-num col-pack">4.5<span class="unit">kg</span></td>
<td class="c-num col-price"><span class="price" data-from="36000" data-to="38000">38,000</span></td>
<td class="c-num col-delta delta up">▲ 2,000</td>
</tr>
<tr>
<th scope="row" class="col-name">
<button
class="board-select"
type="button"
data-market-row
data-name="샤인머스캣"
data-origin="경북 상주"
data-grade="특 등급, 18.2 Bx"
data-pack="2 kg"
data-price="26,500원"
data-delta="▼ 1,500원"
data-auction="02:00 경매"
aria-pressed="false"
>샤인머스캣</button>
</th>
<td class="col-origin">경북 상주</td>
<td class="c-num col-grade">특</td>
<td class="c-num col-brix">18.2<span class="unit">Bx</span></td>
<td class="c-num col-pack">2<span class="unit">kg</span></td>
<td class="c-num col-price"><span class="price" data-from="28000" data-to="26500">26,500</span></td>
<td class="c-num col-delta delta down">▼ 1,500</td>
</tr>
<tr>
<th scope="row" class="col-name">
<button
class="board-select"
type="button"
data-market-row
data-name="캠벨얼리"
data-origin="충북 영동"
data-grade="상 등급, 15.4 Bx"
data-pack="5 kg"
data-price="31,000원"
data-delta="보합"
data-auction="02:00 경매"
aria-pressed="false"
>캠벨얼리</button>
</th>
<td class="col-origin">충북 영동</td>
<td class="c-num col-grade">상</td>
<td class="c-num col-brix">15.4<span class="unit">Bx</span></td>
<td class="c-num col-pack">5<span class="unit">kg</span></td>
<td class="c-num col-price"><span class="price" data-from="31000" data-to="31000">31,000</span></td>
<td class="c-num col-delta delta flat">보합</td>
</tr>
<tr>
<th scope="row" class="col-name">
<button
class="board-select"
type="button"
data-market-row
data-name="홍로 사과"
data-origin="경북 영주"
data-grade="특 등급, 14.1 Bx"
data-pack="5 kg"
data-price="44,000원"
data-delta="▲ 3,500원"
data-auction="08:30 경매"
aria-pressed="false"
>홍로 사과</button>
</th>
<td class="col-origin">경북 영주</td>
<td class="c-num col-grade">특</td>
<td class="c-num col-brix">14.1<span class="unit">Bx</span></td>
<td class="c-num col-pack">5<span class="unit">kg</span></td>
<td class="c-num col-price"><span class="price" data-from="40500" data-to="44000">44,000</span></td>
<td class="c-num col-delta delta up">▲ 3,500</td>
</tr>
<tr>
<th scope="row" class="col-name">
<button
class="board-select"
type="button"
data-market-row
data-name="원황 배"
data-origin="전남 나주"
data-grade="상 등급, 12.8 Bx"
data-pack="7.5 kg"
data-price="52,000원"
data-delta="▼ 2,000원"
data-auction="08:30 경매"
aria-pressed="false"
>원황 배</button>
</th>
<td class="col-origin">전남 나주</td>
<td class="c-num col-grade">상</td>
<td class="c-num col-brix">12.8<span class="unit">Bx</span></td>
<td class="c-num col-pack">7.5<span class="unit">kg</span></td>
<td class="c-num col-price"><span class="price" data-from="54000" data-to="52000">52,000</span></td>
<td class="c-num col-delta delta down">▼ 2,000</td>
</tr>
<tr>
<th scope="row" class="col-name">
<button
class="board-select"
type="button"
data-market-row
data-name="무화과"
data-origin="전남 영암"
data-grade="특 등급, 당도 표기 대상 아님"
data-pack="1.2 kg"
data-price="24,000원"
data-delta="▲ 1,000원"
data-auction="02:00 경매"
aria-pressed="false"
>무화과</button>
</th>
<td class="col-origin">전남 영암</td>
<td class="c-num col-grade">특</td>
<td class="c-num col-brix blank"><span class="sr-only">당도 표기 대상 아님</span><span aria-hidden="true">—</span></td>
<td class="c-num col-pack">1.2<span class="unit">kg</span></td>
<td class="c-num col-price"><span class="price" data-from="23000" data-to="24000">24,000</span></td>
<td class="c-num col-delta delta up">▲ 1,000</td>
</tr>
</tbody>
</table>
</div>
<div class="lot-inspector" aria-live="polite" aria-atomic="true">
<div class="lot-title">
<p class="lot-label">선택한 품목</p>
<p class="lot-name" id="lotName">백도 복숭아</p>
<p class="lot-origin" id="lotOrigin">경북 청도</p>
</div>
<dl class="lot-spec">
<div>
<dt>등급과 당도</dt>
<dd id="lotGrade">특 등급, 12.5 Bx</dd>
</div>
<div>
<dt>규격</dt>
<dd id="lotPack">4.5 kg</dd>
</div>
<div>
<dt>경매</dt>
<dd id="lotAuction">02:00 경매</dd>
</div>
<div>
<dt>전일 대비</dt>
<dd id="lotDelta">▲ 2,000원</dd>
</div>
</dl>
<p class="lot-price">
<span class="lot-price-label">낙찰가</span>
<span class="lot-price-value" id="lotPrice">38,000원</span>
</p>
</div>
</div>
<div class="panel" id="panelDates" role="tabpanel" aria-labelledby="tabDates" hidden>
<div class="board-scroll">
<table class="board board-dates">
<caption class="sr-only">품목별 전일 낙찰가와 오늘 낙찰가, 차이</caption>
<thead>
<tr>
<th scope="col" class="col-name">품목</th>
<th scope="col" class="col-origin">경매</th>
<th scope="col" class="c-num">전일</th>
<th scope="col" class="c-num col-price">오늘</th>
<th scope="col" class="c-num col-delta">차이</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" class="col-name">백도 복숭아</th>
<td class="col-origin">02:00</td>
<td class="c-num">36,000</td>
<td class="c-num col-price"><span class="price" data-from="36000" data-to="38000">38,000</span></td>
<td class="c-num col-delta delta up">▲ 2,000</td>
</tr>
<tr>
<th scope="row" class="col-name">샤인머스캣</th>
<td class="col-origin">02:00</td>
<td class="c-num">28,000</td>
<td class="c-num col-price"><span class="price" data-from="28000" data-to="26500">26,500</span></td>
<td class="c-num col-delta delta down">▼ 1,500</td>
</tr>
<tr>
<th scope="row" class="col-name">캠벨얼리</th>
<td class="col-origin">02:00</td>
<td class="c-num">31,000</td>
<td class="c-num col-price"><span class="price" data-from="31000" data-to="31000">31,000</span></td>
<td class="c-num col-delta delta flat">보합</td>
</tr>
<tr>
<th scope="row" class="col-name">홍로 사과</th>
<td class="col-origin">08:30</td>
<td class="c-num">40,500</td>
<td class="c-num col-price"><span class="price" data-from="40500" data-to="44000">44,000</span></td>
<td class="c-num col-delta delta up">▲ 3,500</td>
</tr>
<tr>
<th scope="row" class="col-name">원황 배</th>
<td class="col-origin">08:30</td>
<td class="c-num">54,000</td>
<td class="c-num col-price"><span class="price" data-from="54000" data-to="52000">52,000</span></td>
<td class="c-num col-delta delta down">▼ 2,000</td>
</tr>
<tr>
<th scope="row" class="col-name">무화과</th>
<td class="col-origin">02:00</td>
<td class="c-num">23,000</td>
<td class="c-num col-price"><span class="price" data-from="23000" data-to="24000">24,000</span></td>
<td class="c-num col-delta delta up">▲ 1,000</td>
</tr>
</tbody>
</table>
</div>
<p class="board-note">
전일 낙찰가는 오늘 낙찰가에서 전일 대비를 뺀 값입니다. 단위는 원이고 규격은 품목별 시세와
같습니다.
</p>
</div>
<ul class="board-notes">
<li>
당도 칸의 <strong>—</strong>는 값이 없다는 뜻이 아니라 표시가 허용되지 않는 품목이라는
뜻입니다. 무화과는 당도 표기 대상 13개 품목에 들어 있지 않습니다.
</li>
<li>
이 표의 품목, 가격, 시간은 이해를 돕기 위한 예시 낙찰가입니다. 실제 주문과 납품은 받지
않습니다.
</li>
</ul>
</div>
</section>
<!-- 2 · 읽는 법 + 유통 단계. 새벽 통로 사진을 왼쪽 가장자리로 흘린다 -->
<section class="section section-grade" id="grade" aria-labelledby="gradeHeading">
<div class="bleed-row">
<figure class="bleed bleed-left">
<img
src="./assets/dawn-aisle.webp"
width="1600"
height="900"
loading="lazy"
decoding="async"
alt="새벽 두 시, 형광등이 켜진 도매시장 통로에 과일 상자가 양쪽으로 쌓여 있습니다"
/>
<figcaption>02:00 경매가 열리는 도매시장 통로</figcaption>
</figure>
<div class="bleed-body">
<h2 id="gradeHeading">등급, 당도, 규격은 농산물 표준규격 기준으로 적습니다</h2>
<dl class="terms">
<div>
<dt>등급 <span class="term-en">특, 상, 보통</span></dt>
<dd>
크기가 고른지, 흠이 없는지, 색이 제대로 들었는지를 봅니다. 기준은 농산물 표준규격에
품목별로 정해져 있습니다. <strong>당도를 표시할 수 있는 것은 특과 상 등급뿐</strong>입니다.
</dd>
</div>
<div>
<dt>당도 <span class="term-en">Brix</span></dt>
<dd>
용액 100g에 든 당이 몇 g인지를 나타냅니다. 굴절당도계에 과즙 한 방울을 올려 잽니다.
당도가 높다고 늘 맛있는 것은 아니고 산도와의 균형에 따라 맛이 달라지므로, 당도 숫자만
강조하지 않습니다.
</dd>
</div>
<div>
<dt>선과</dt>
<dd>
기계로 골라내는 일입니다. 드럼식은 지름으로, 중량식은 무게로 나눕니다. 그래서 한 상자
안의 과일 크기가 고릅니다.
</dd>
</div>
<div>
<dt>규격 <span class="term-en">kg</span></dt>
<dd>
상자 단위입니다. 사과는 2, 5, 7.5, 10kg, 포도는 2, 3, 4, 5kg로 거래됩니다. 같은
가격이라도 규격이 다르면 비교할 수 없어서 시세표에 함께 적습니다.
</dd>
</div>
</dl>
</div>
</div>
<div class="wrap route-wrap" id="route">
<h3 id="routeHeading">산지에서 배송까지 다섯 단계 가운데 새벽청과는 넷째 단계인 낙찰을 맡습니다</h3>
<ol class="route">
<li>
<h4>출하</h4>
<p>산지에서 따고 골라 담아 시장으로 보냅니다.</p>
</li>
<li>
<h4>수집</h4>
<p>도매법인이 그날 들어온 물량을 받아 경매에 올립니다.</p>
</li>
<li>
<h4>경매</h4>
<p>새벽 2시 경매에서 가격이 정해집니다. 이때 낙찰된 가격이 경락가격입니다.</p>
</li>
<li class="route-here">
<h4>낙찰</h4>
<p>중도매인 자격으로 직접 낙찰받습니다. 어느 산지의 어떤 등급을 얼마에 받았는지 위 시세표에 그대로 올립니다.</p>
</li>
<li>
<h4>그날 아침 배송</h4>
<p>창고에 따로 보관하지 않고, 경매장에서 받은 상자를 그날 아침 바로 보냅니다.</p>
</li>
</ol>
</div>
</section>
<!-- 3 · 오늘 입고 사진(흘림) + 제철 달력 -->
<section class="section section-today" id="today" aria-labelledby="todayHeading">
<div class="wrap">
<h2 id="todayHeading">오늘 들어온 나주 배와 영동 포도, 당도는 굴절당도계로 잽니다</h2>
</div>
<figure class="bleed-row bleed-figure">
<div class="bleed bleed-right">
<img
src="./assets/pear-crate.webp"
width="1100"
height="825"
loading="lazy"
decoding="async"
alt="흰 그물망에 하나씩 싼 배가 얕은 나무 상자에 담겨 있고, 한 알은 상자 옆에 꺼내 놓여 있습니다"
/>
</div>
<figcaption class="bleed-body">
<p class="card-name">원황 배 <span class="card-origin">전남 나주</span></p>
<dl class="card-spec">
<div><dt>등급</dt><dd>상</dd></div>
<div><dt>당도</dt><dd>12.8 Bx</dd></div>
<div><dt>규격</dt><dd>7.5 kg</dd></div>
</dl>
<p class="card-note">
나주 배는 과즙이 많고 단맛이 뒤에 올라옵니다. 그물망은 배가 눌리지 않게 감싸는
포장재입니다.
</p>
</figcaption>
</figure>
<figure class="bleed-row bleed-figure bleed-figure-rev">
<div class="bleed bleed-left bleed-portrait">
<img
src="./assets/grape-bloom.webp"
width="900"
height="1200"
loading="lazy"
decoding="async"
alt="흰 종이 위에 놓인 진자주색 포도 송이. 껍질에 하얀 과분이 그대로 남아 있습니다"
/>
</div>
<figcaption class="bleed-body">
<p class="card-name">캠벨얼리 <span class="card-origin">충북 영동</span></p>
<dl class="card-spec">
<div><dt>등급</dt><dd>상</dd></div>
<div><dt>당도</dt><dd>15.4 Bx</dd></div>
<div><dt>규격</dt><dd>5 kg</dd></div>
</dl>
<p class="card-note">
껍질의 흰 가루는 과분이라는 천연 성분입니다. 과분이 많이 남아 있을수록 손을 덜 탄
포도입니다.
</p>
</figcaption>
</figure>
<figure class="bleed-row bleed-figure">
<div class="bleed bleed-right">
<img
src="./assets/refractometer.webp"
width="1100"
height="825"
loading="lazy"
decoding="async"
alt="스테인리스 작업대 위 굴절당도계의 프리즘 판에 과즙 한 방울이 올려져 있습니다"
/>
</div>
<figcaption class="bleed-body">
<p class="card-name">당도는 이렇게 잽니다</p>
<p class="card-note">
굴절당도계에 과즙을 한 방울 올려 빛이 꺾이는 정도를 읽습니다. 상자마다 재지 않고 입고된
로트에서 표본을 뽑아 재므로, 시세표의 당도는 해당 로트의 표본값입니다.
</p>
</figcaption>
</figure>
<div class="wrap season-wrap" id="season">
<h3 id="seasonHeading">제철 품목만 들여오므로, 칸이 채워진 달에만 그 품목이 시세표에 올라갑니다</h3>
<div class="season-control">
<div class="season-buttons" role="group" aria-label="제철 달 선택">
<button type="button" data-season-dir="-1">이전 달</button>
<button type="button" data-season-dir="1">다음 달</button>
</div>
<p class="season-status" aria-live="polite" aria-atomic="true">
<output id="seasonMonth">10월</output>
<span id="seasonCount">제철 품목을 읽는 중입니다</span>
</p>
</div>
<div class="season-scroll">
<table class="season">
<caption class="sr-only">품목별 제철 달력. 가로축은 1월부터 12월</caption>
<thead>
<tr>
<th scope="col" class="season-item">품목</th>
<th scope="col" data-m="1">1</th>
<th scope="col" data-m="2">2</th>
<th scope="col" data-m="3">3</th>
<th scope="col" data-m="4">4</th>
<th scope="col" data-m="5">5</th>
<th scope="col" data-m="6">6</th>
<th scope="col" data-m="7">7</th>
<th scope="col" data-m="8">8</th>
<th scope="col" data-m="9">9</th>
<th scope="col" data-m="10">10</th>
<th scope="col" data-m="11">11</th>
<th scope="col" data-m="12">12</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">딸기</th>
<td class="on" data-m="1"><span class="sr-only">제철</span></td>
<td class="on" data-m="2"><span class="sr-only">제철</span></td>
<td class="on" data-m="3"><span class="sr-only">제철</span></td>
<td class="on" data-m="4"><span class="sr-only">제철</span></td>
<td data-m="5"></td><td data-m="6"></td><td data-m="7"></td><td data-m="8"></td>
<td data-m="9"></td><td data-m="10"></td><td data-m="11"></td>
<td class="on" data-m="12"><span class="sr-only">제철</span></td>
</tr>
<tr>
<th scope="row">참외</th>
<td data-m="1"></td><td data-m="2"></td><td data-m="3"></td>
<td class="on" data-m="4"><span class="sr-only">제철</span></td>
<td class="on" data-m="5"><span class="sr-only">제철</span></td>
<td class="on" data-m="6"><span class="sr-only">제철</span></td>
<td class="on" data-m="7"><span class="sr-only">제철</span></td>
<td data-m="8"></td><td data-m="9"></td><td data-m="10"></td>
<td data-m="11"></td><td data-m="12"></td>
</tr>
<tr>
<th scope="row">복숭아</th>
<td data-m="1"></td><td data-m="2"></td><td data-m="3"></td>
<td data-m="4"></td><td data-m="5"></td>
<td class="on" data-m="6"><span class="sr-only">제철</span></td>
<td class="on" data-m="7"><span class="sr-only">제철</span></td>
<td class="on" data-m="8"><span class="sr-only">제철</span></td>
<td class="on" data-m="9"><span class="sr-only">제철</span></td>
<td data-m="10"></td><td data-m="11"></td><td data-m="12"></td>
</tr>
<tr>
<th scope="row">포도</th>
<td data-m="1"></td><td data-m="2"></td><td data-m="3"></td>
<td data-m="4"></td><td data-m="5"></td><td data-m="6"></td>
<td class="on" data-m="7"><span class="sr-only">제철</span></td>
<td class="on" data-m="8"><span class="sr-only">제철</span></td>
<td class="on" data-m="9"><span class="sr-only">제철</span></td>
<td class="on" data-m="10"><span class="sr-only">제철</span></td>
<td data-m="11"></td><td data-m="12"></td>
</tr>
<tr>
<th scope="row">무화과</th>
<td data-m="1"></td><td data-m="2"></td><td data-m="3"></td>
<td data-m="4"></td><td data-m="5"></td><td data-m="6"></td>
<td data-m="7"></td>
<td class="on" data-m="8"><span class="sr-only">제철</span></td>
<td class="on" data-m="9"><span class="sr-only">제철</span></td>
<td class="on" data-m="10"><span class="sr-only">제철</span></td>
<td data-m="11"></td><td data-m="12"></td>
</tr>
<tr>
<th scope="row">사과</th>
<td data-m="1"></td><td data-m="2"></td><td data-m="3"></td>
<td data-m="4"></td><td data-m="5"></td><td data-m="6"></td>
<td data-m="7"></td>
<td class="on" data-m="8"><span class="sr-only">제철</span></td>
<td class="on" data-m="9"><span class="sr-only">제철</span></td>
<td class="on" data-m="10"><span class="sr-only">제철</span></td>
<td class="on" data-m="11"><span class="sr-only">제철</span></td>
<td class="on" data-m="12"><span class="sr-only">제철</span></td>
</tr>
<tr>
<th scope="row">배</th>
<td data-m="1"></td><td data-m="2"></td><td data-m="3"></td>
<td data-m="4"></td><td data-m="5"></td><td data-m="6"></td>
<td data-m="7"></td>
<td class="on" data-m="8"><span class="sr-only">제철</span></td>
<td class="on" data-m="9"><span class="sr-only">제철</span></td>
<td class="on" data-m="10"><span class="sr-only">제철</span></td>
<td class="on" data-m="11"><span class="sr-only">제철</span></td>
<td data-m="12"></td>
</tr>
<tr>
<th scope="row">감귤</th>
<td class="on" data-m="1"><span class="sr-only">제철</span></td>
<td class="on" data-m="2"><span class="sr-only">제철</span></td>
<td data-m="3"></td><td data-m="4"></td><td data-m="5"></td>
<td data-m="6"></td><td data-m="7"></td><td data-m="8"></td>
<td data-m="9"></td>
<td class="on" data-m="10"><span class="sr-only">제철</span></td>
<td class="on" data-m="11"><span class="sr-only">제철</span></td>
<td class="on" data-m="12"><span class="sr-only">제철</span></td>
</tr>
</tbody>
</table>
</div>
<p class="season-note">
굵은 세로선이 이번 달입니다. 산지와 그해 날씨에 따라 2주 정도 앞당겨지거나 늦어질 수
있습니다.
</p>
</div>
</section>
<!-- 4 · 납품 조건 + 수량 계산 -->
<section class="section section-wholesale" id="wholesale" aria-labelledby="wsHeading">
<div class="wrap">
<h2 id="wsHeading">매장 납품은 전날 21:00에 마감하고 품목당 3상자부터 받습니다</h2>
<div class="ws-grid">
<div class="ws-body">
<p class="lead">
카페, 베이커리, 식당처럼 매일 같은 품질이 필요한 곳은 소매와 다른 조건으로 납품합니다.
이런 곳에는 가격보다 <strong>품질 편차</strong>가 더 중요하기 때문입니다.
</p>
<dl class="ws-rows">
<div>
<dt>주문 마감</dt>
<dd>전날 21:00. 새벽 경매 물량을 확보하기 위한 마감입니다.</dd>
</div>
<div>
<dt>배송</dt>
<dd>같은 날 오전. 수도권은 직접 배송하고, 그 외 지역은 새벽 배송 업체로 보냅니다.</dd>
</div>
<div>
<dt>등급 고정</dt>
<dd>등급을 계약으로 묶습니다. 그날 시세가 올라도 등급을 낮춰 값을 맞추지 않습니다.</dd>
</div>
<div>
<dt>시세 공유</dt>
<dd>낙찰가를 그대로 전달합니다. 마진은 별도 항목으로 적습니다.</dd>
</div>
<div>
<dt>최소 물량</dt>
<dd>품목당 상자 3개부터.</dd>
</div>
</dl>
</div>
<section class="order-draft" aria-labelledby="orderDraftHeading">
<h3 id="orderDraftHeading">수량별 기준 금액 보기</h3>
<div class="order-controls">
<label>
<span>품목</span>
<select id="orderItem">
<option value="백도 복숭아" data-price="38000" data-pack="4.5 kg">백도 복숭아, 특, 4.5 kg</option>
<option value="샤인머스캣" data-price="26500" data-pack="2 kg">샤인머스캣, 특, 2 kg</option>
<option value="캠벨얼리" data-price="31000" data-pack="5 kg">캠벨얼리, 상, 5 kg</option>
<option value="홍로 사과" data-price="44000" data-pack="5 kg">홍로 사과, 특, 5 kg</option>
<option value="원황 배" data-price="52000" data-pack="7.5 kg">원황 배, 상, 7.5 kg</option>
<option value="무화과" data-price="24000" data-pack="1.2 kg">무화과, 특, 1.2 kg</option>
</select>
</label>
<label>
<span>상자 수</span>
<input id="orderQty" type="number" min="3" max="50" step="1" value="3" inputmode="numeric" />
</label>
</div>
<dl class="order-summary">
<div>
<dt>규격</dt>
<dd id="orderPack">4.5 kg × 3상자</dd>
</div>
<div>
<dt>표시된 낙찰가 합계</dt>
<dd class="order-total" id="orderTotal">114,000원</dd>
</div>
</dl>
<p class="order-fine">
위 합계는 표에 적힌 예시 낙찰가만 더한 값입니다. 선별, 포장, 배송과 실제 납품가는 포함하지
않습니다.
</p>
<div class="order-actions">
<button class="btn" id="copyOrder" type="button">계산 내용 복사</button>
<p class="order-status" id="orderStatus" role="status"></p>
</div>
</section>
</div>
</div>
</section>
</main>
<!-- 푸터 = 연락처·영업시간 카드. 경매 시간과 영업시간이 마지막에 찾는 사실이다 -->
<footer class="site-foot" id="contact">
<div class="wrap">
<div class="foot-card">
<div class="foot-brand">
<p class="foot-name">새벽청과</p>
<p class="foot-line">새벽 경매에서 받아 그날 아침에 보냅니다.</p>
</div>
<dl class="foot-rows">
<div>
<dt>경매 시간</dt>
<dd>02:00 복숭아, 포도, 무화과 등<br />08:30 사과, 배</dd>
</div>
<div>
<dt>영업시간</dt>
<dd>새벽 01:30 – 낮 12:00<br />일요일 휴무</dd>
</div>
<div>
<dt>주문 마감</dt>
<dd>전날 21:00</dd>
</div>
<div>
<dt>시장 위치</dt>
<dd>가락시장 청과동 2층 214호</dd>
</div>
<div>
<dt>전화</dt>
<dd>02-000-5230</dd>
</div>
<div>
<dt>메일</dt>
<dd>order@saebyeok.example</dd>
</div>
</dl>
</div>
<p class="foot-fine">
이 페이지의 품목, 가격, 시간은 이해를 돕기 위한 예시이며 실제 주문과 납품 서비스가 아닙니다.
점포 위치, 전화, 메일도 예시이며 실제로 연결되지 않습니다. 경매 시각, 등급, 당도 표시
규정 등 제도에 관한 설명은 실제 농산물 표준규격과 도매시장 운영 방식을 따릅니다.
</p>
</div>
</footer>
<script>
(() => {
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
/* 날짜 도장 — 한국 시간 오늘을 머리줄에 적는다. */
const marketTime = new Date();
const dateParts = Object.fromEntries(
new Intl.DateTimeFormat("en-CA", {
timeZone: "Asia/Seoul",
year: "numeric",
month: "2-digit",
day: "2-digit",
})
.formatToParts(marketTime)
.filter((part) => part.type !== "literal")
.map((part) => [part.type, part.value]),
);
const currentMonth = Number(dateParts.month);
const heroMetaTime = document.querySelector(".hero-meta time");
if (heroMetaTime) {
heroMetaTime.dateTime = `${dateParts.year}-${dateParts.month}-${dateParts.day}T02:00+09:00`;
heroMetaTime.textContent = `${dateParts.month}월 ${dateParts.day}일 02:00`;
}
/* 낙찰가 카운터 — 전일가에서 오늘가로 올라가거나 내려간다.
감소 모션 설정이면 최종값이 이미 마크업에 있으므로 아무것도 하지 않는다. */
const counted = new WeakSet();
function countPrices(root) {
if (!root) return;
for (const node of root.querySelectorAll(".price[data-from][data-to]")) {
if (counted.has(node)) continue;
counted.add(node);
const from = Number(node.dataset.from);
const to = Number(node.dataset.to);
if (reduceMotion || from === to || !Number.isFinite(from) || !Number.isFinite(to)) continue;
const duration = 600;
const start = performance.now();
const step = (now) => {
const t = Math.min(1, (now - start) / duration);
const eased = 1 - (1 - t) * (1 - t) * (1 - t);
const value = Math.round((from + (to - from) * eased) / 100) * 100;
node.textContent = (t >= 1 ? to : value).toLocaleString("ko-KR");
if (t < 1) requestAnimationFrame(step);
};
node.textContent = from.toLocaleString("ko-KR");
requestAnimationFrame(step);
}
}
/* 탭 — 품목별 / 일자별. 화살표·Home·End로 옮기고 포커스 즉시 전환한다(APG Tabs). */
const tabs = [...document.querySelectorAll('[role="tab"]')];
function selectTab(tab, focus) {
for (const item of tabs) {
const on = item === tab;
item.setAttribute("aria-selected", String(on));
item.tabIndex = on ? 0 : -1;
const panel = document.getElementById(item.getAttribute("aria-controls"));
if (panel) panel.hidden = !on;
if (on && panel) countPrices(panel);
}
if (focus) tab.focus();
}
tabs.forEach((tab, index) => {
tab.addEventListener("click", () => selectTab(tab, false));
tab.addEventListener("keydown", (event) => {
const last = tabs.length - 1;
let next = null;
if (event.key === "ArrowRight") next = index === last ? 0 : index + 1;
else if (event.key === "ArrowLeft") next = index === 0 ? last : index - 1;
else if (event.key === "Home") next = 0;
else if (event.key === "End") next = last;
if (next === null) return;
event.preventDefault();
selectTab(tabs[next], true);
});
});
countPrices(document.getElementById("panelItems"));
/* 표의 한 행을 고르면 같은 값으로 선택 로트가 바뀐다. */
const marketRows = [...document.querySelectorAll("[data-market-row]")];
const lotFields = {
auction: document.getElementById("lotAuction"),
name: document.getElementById("lotName"),
origin: document.getElementById("lotOrigin"),
grade: document.getElementById("lotGrade"),
pack: document.getElementById("lotPack"),
price: document.getElementById("lotPrice"),
delta: document.getElementById("lotDelta"),
};
function showLot(button) {
for (const row of marketRows) row.setAttribute("aria-pressed", String(row === button));
for (const [key, field] of Object.entries(lotFields)) {
if (field) field.textContent = button.dataset[key] || "";
}
if (orderItem) orderItem.value = button.dataset.name || orderItem.value;
updateOrder();
}
for (const row of marketRows) row.addEventListener("click", () => showLot(row));
/* 제철 달력은 이번 달에서 시작하지만 앞뒤 달도 직접 읽을 수 있다. */
let selectedMonth = currentMonth;
const season = document.querySelector(".season");
const seasonScroll = document.querySelector(".season-scroll");
const seasonMonth = document.getElementById("seasonMonth");
const seasonCount = document.getElementById("seasonCount");
function showMonth(month, moveViewport) {
selectedMonth = month;
season?.querySelectorAll(".is-focus").forEach((cell) => cell.classList.remove("is-focus"));
season?.querySelectorAll("[aria-current='date']").forEach((cell) => cell.removeAttribute("aria-current"));
season?.querySelectorAll(`[data-m="${month}"]`).forEach((cell) => cell.classList.add("is-focus"));
const head = season?.querySelector(`thead [data-m="${month}"]`);
if (month === currentMonth) head?.setAttribute("aria-current", "date");
const items = [...(season?.querySelectorAll("tbody tr") || [])]
.filter((row) => row.querySelector(`td.on[data-m="${month}"]`))
.map((row) => row.querySelector("th")?.textContent.trim())
.filter(Boolean);
if (seasonMonth) seasonMonth.textContent = `${month}월`;
if (seasonCount) seasonCount.textContent = `${items.length}품목: ${items.join(", ")}`;
if (moveViewport && head && seasonScroll) {
const left = Math.max(0, head.offsetLeft - seasonScroll.clientWidth / 2 + head.clientWidth / 2);
seasonScroll.scrollTo({ left, behavior: reduceMotion ? "auto" : "smooth" });
}
}
document.querySelectorAll("[data-season-dir]").forEach((button) => {
button.addEventListener("click", () => {
const next = ((selectedMonth - 1 + Number(button.dataset.seasonDir) + 12) % 12) + 1;
showMonth(next, true);
});
});
showMonth(currentMonth, true);
/* 가로로 넘치는 표만 키보드 포커스를 받게 한다 — 넘치지 않는 폭에서는 탭 정지점을 만들지 않는다 */
const scrollers = [...document.querySelectorAll(".board-scroll, .season-scroll")];
function syncScrollFocus() {
for (const box of scrollers) {
const overflowing = box.scrollWidth > box.clientWidth + 1;
if (overflowing) {
box.tabIndex = 0;
box.setAttribute("role", "region");
box.setAttribute("aria-label", box.classList.contains("season-scroll") ? "제철 달력, 가로로 넘깁니다" : "시세표, 가로로 넘깁니다");
} else {
box.removeAttribute("tabindex");
box.removeAttribute("role");
box.removeAttribute("aria-label");
}
}
}
syncScrollFocus();
window.addEventListener("resize", syncScrollFocus);
/* 낙찰가 예시로 발주 메모를 만든다. 납품가처럼 보이지 않게 항목을 분리한다. */
const orderItem = document.getElementById("orderItem");
const orderQty = document.getElementById("orderQty");
const orderPack = document.getElementById("orderPack");
const orderTotal = document.getElementById("orderTotal");
const orderStatus = document.getElementById("orderStatus");
function orderValues() {
const option = orderItem?.selectedOptions[0];
const quantity = Math.min(50, Math.max(3, Number(orderQty?.value) || 3));
const price = Number(option?.dataset.price) || 0;
return {
name: option?.value || "",
pack: option?.dataset.pack || "",
quantity,
total: price * quantity,
};
}
function updateOrder() {
const value = orderValues();
if (orderPack) orderPack.textContent = `${value.pack} × ${value.quantity}상자`;
if (orderTotal) orderTotal.textContent = `${value.total.toLocaleString("ko-KR")}원`;
if (orderStatus) orderStatus.textContent = "";
}
orderItem?.addEventListener("change", updateOrder);
orderQty?.addEventListener("input", updateOrder);
orderQty?.addEventListener("change", () => {
if (orderQty) orderQty.value = String(orderValues().quantity);
updateOrder();
});
async function copyText(text) {
if (navigator.clipboard?.writeText) {
try {
await Promise.race([
navigator.clipboard.writeText(text),
new Promise((_, reject) => window.setTimeout(() => reject(new Error("clipboard timeout")), 1200)),
]);
return true;
} catch {
// 권한 대화상자가 없거나 응답하지 않는 브라우저는 아래 선택 복사로 전환합니다.
}
}
const field = document.createElement("textarea");
field.value = text;
field.setAttribute("readonly", "");
field.style.position = "fixed";
field.style.inset = "0 auto auto -9999px";
document.body.append(field);
field.select();
const copied = document.execCommand("copy");
field.remove();
return copied;
}
document.getElementById("copyOrder")?.addEventListener("click", async () => {
const value = orderValues();
const memo = [
"새벽청과 예시 발주 메모",
`품목: ${value.name}`,
`규격: ${value.pack}`,
`수량: ${value.quantity}상자`,
`표시된 낙찰가 합계: ${value.total.toLocaleString("ko-KR")}원`,
"실제 납품가는 선별, 포장, 배송 조건을 확인한 뒤 정합니다.",
].join("\n");
try {
const copied = await copyText(memo);
if (orderStatus) {
orderStatus.textContent = copied
? "계산 내용을 복사했습니다."
: "복사하지 못했습니다. 브라우저의 클립보드 권한을 확인해 주세요.";
}
} catch {
if (orderStatus) orderStatus.textContent = "복사하지 못했습니다. 브라우저의 클립보드 권한을 확인해 주세요.";
}
});
updateOrder();
})();
</script>
</body>
</html>