/* ===========================================================================
   Iklan Harian — newsprint design system
   ---------------------------------------------------------------------------
   Newspaper-inspired, but its own identity. The rules that make it read as
   print rather than as a web app:
     - hairline rules and hard edges only; no shadows, no rounded corners
     - one spot colour, used sparingly, the way two-colour presses worked
     - condensed type at classified density, set in real columns
     - the page is a grid of bands; line ads flow inside them
   =========================================================================== */

:root {
  /* --- paper & ink ------------------------------------------------------ */
  /* White stock, black ink, one spot colour. Nothing else. */
  --paper:        #ffffff;
  --paper-2:      #f1f1ef;   /* screened/tinted panel, as a raster block */
  --ink:          #111111;
  --ink-soft:     #565656;
  --ink-faint:    #8a8a8a;
  --rule:         #111111;
  --rule-soft:    #cfcfcf;
  --spot:         #b32217;   /* the one colour on the press */
  --spot-soft:    #fceceb;

  /* --- type ------------------------------------------------------------- */
  /* Condensed grotesque for classified copy. Arial Narrow is the one truly
     ubiquitous condensed face; the rest are platform upgrades ahead of it. */
  --font-classified: "Roboto Condensed", "Avenir Next Condensed",
                     "Helvetica Neue Condensed", "Arial Narrow", Arial, sans-serif;
  /* Old-style serif for the masthead and rubric headings. */
  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua",
                  ui-serif, Georgia, "Times New Roman", serif;
  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --measure: 25ch;   /* classified column width — drives the whole grid */
  --gutter: .9rem;
  --band-gap: 0.5rem;
}

/* This page commits to one look: white paper. A newspaper has no night
   edition, so there is deliberately no dark-mode inversion here — the stock
   stays white whatever the reader's system preference says. */

*, *::before, *::after { box-sizing: border-box; }

/* Radios, checkboxes and date pickers otherwise render in browser blue, which
   is the one colour this palette does not contain. */
:root { accent-color: var(--spot); }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-classified);
  font-size: 16px;
  line-height: 1.4;
}

a { color: inherit; text-underline-offset: 2px; }
a:hover { color: var(--spot); }

/* ---------------------------------------------------------------- masthead */

.sheet {
  max-width: 1360px;
  margin: 0 auto;
  padding: 0 1rem 4rem;
}

.masthead {
  border-bottom: 3px solid var(--rule);
  padding-top: 2rem;
}
.masthead__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 6.5vw, 4.25rem);
  /* line-height below 1 pulls the box in tighter than the glyphs, so the J
     descender overhangs and collides with the rule underneath. */
  line-height: 1;
  letter-spacing: -.02em;
  margin: 0 0 1.1rem;
  text-align: center;
  text-transform: uppercase;
}
.masthead__name em { font-style: normal; color: var(--spot); }
.masthead__rule {
  display: flex; justify-content: space-between; gap: 1rem;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  margin-top: .75rem; padding: .3rem 0;
  font-size: .72rem; text-transform: uppercase; letter-spacing: .14em;
  color: var(--ink-soft);
}

/* Section navigation, set as a rule of small caps. */
.nav {
  display: flex; flex-wrap: wrap; gap: 0 1.25rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: .8rem; text-transform: uppercase; letter-spacing: .1em;
}
.nav a { text-decoration: none; padding: .15rem 0; }
.nav a[aria-current="page"] { color: var(--spot); font-weight: 700; }

/* ------------------------------------------------------------------ rubric */

/* The reversed black bar that opens every category. */
.rubrik {
  background: var(--ink); color: var(--paper);
  font-family: var(--font-display);
  font-size: 1.05rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em;
  padding: .3rem .6rem;
  margin: var(--band-gap) 0 0;
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
}
.rubrik__count { font-family: var(--font-classified); font-size: .75rem; letter-spacing: .06em; opacity: .8; }
.rubrik a { color: inherit; text-decoration: none; }
.rubrik-block { break-inside: auto; }

/* The lighter area sub-heading inside a rubric. */
/* Area sub-heads sit inside the column flow. break-after:avoid keeps a heading
   from being orphaned at the foot of a column, away from its first ad.
   A page carries dozens of these, so they are set as a quiet ruled caption
   rather than a filled bar — the reversed bar is reserved for the rubric. */
.area-head {
  font-weight: 700; font-size: .66rem;
  text-transform: uppercase; letter-spacing: .12em;
  color: var(--ink-soft);
  border-top: 1px solid var(--rule);
  padding-top: .25rem;
  margin: .9rem 0 .4rem;
  break-after: avoid;
  break-inside: avoid;
}
.area-head:first-child { margin-top: 0; border-top: 0; padding-top: 0; }

/* ------------------------------------------------------------------- bands */

/* A page is a stack of bands. Line ads flow in real columns; boxed ads sit on
   a 6-track grid. Column count is derived from the measure, so the layout
   reflows from six columns to one without a single media query. */

.band { margin-top: var(--band-gap); }

/* One rubric, one continuous run of columns. The browser fits as many columns
   of the sold measure as the viewport allows, so the page reflows from six
   columns to one without a single media query. */
.band--baris {
  columns: var(--measure);
  column-gap: var(--gutter);
  column-rule: 1px solid var(--rule-soft);
  padding-top: .55rem;
  orphans: 2;
  widows: 2;
}

/* The display band at the head of the page.
   auto-fill keeps the track count tied to the sold column measure, so a box
   occupies the same share of the page whether or not the row is full. The
   trade is that a part-filled row stops short of the page edge.
   Cells stretch to a common height so the band reads as one composed block
   instead of three boxes of unrelated sizes. */
.band--kolom {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--measure), 1fr));
  grid-auto-flow: row dense;
  align-items: stretch;
  gap: var(--gutter);
  padding-top: .4rem;
  padding-bottom: .8rem;
  margin-bottom: .9rem;
  border-bottom: 1px solid var(--rule);
}

/* Says plainly that the band is bought space, not the paper's own copy. */
.display-label {
  font-size: .6rem;
  text-transform: uppercase;
  letter-spacing: .18em;
  color: var(--ink-faint);
  border-top: 1px solid var(--rule);
  padding-top: .25rem;
  margin-top: var(--band-gap);
}

/* --------------------------------------------------------------- line ads */

/* One ad. Nothing rules it off from its neighbour: the bold entry head and the
   space beneath are the separator, which is how a set classified column reads
   without turning into a ladder of hairlines. */
.ad-baris {
  display: block;
  color: inherit;
  text-decoration: none;
  break-inside: avoid;
  margin: 0 0 .62rem;
  font-size: .78rem;
  line-height: 1.22;
  hyphens: none;
}

/* The opening phrase, set bold — the entry head. */
.ad-baris__head { display: block; font-weight: 700; }

/* The remaining lines, carrying the exact breaks the ad was priced on.
   pre-wrap keeps those breaks and still soft-wraps rather than overflowing. */
.ad-baris__body {
  display: block;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}
.ad-baris__body:empty { display: none; }

.ad-baris--bold   { font-weight: 700; }
.ad-baris--border { border: 1px solid var(--rule); padding: .4rem; }
.ad-baris--screen { background: var(--paper-2); padding: .4rem; }

.ad-baris:hover { background: var(--paper-2); color: inherit; }
.ad-baris__contact { display: block; }

/* --------------------------------------------------------------- boxed ads */

.ad-kolom {
  grid-column: span var(--span, 1);
  border: 1px solid var(--rule);
  padding: .8rem;
  display: flex;
  flex-direction: column;
  justify-content: center;   /* not space-between: the gap in the middle was the mess */
  gap: .45rem;
  background: var(--paper);
  color: inherit;
  text-decoration: none;
}
.ad-kolom:hover { border-color: var(--spot); }
.ad-kolom--screen { background: var(--paper-2); }
.ad-kolom__img { width: 100%; height: auto; display: block; filter: grayscale(1) contrast(1.1); }
.ad-kolom__body { display: block; font-size: .85rem; line-height: 1.3; white-space: pre-wrap; }
.ad-kolom__contact { display: block; }
.ad-kolom__contact { font-weight: 700; font-size: .95rem; }

/* A one-column box set inside the classified flow: it must not be broken
   across a column boundary, and it has no grid to span. */
.band--baris .ad-kolom {
  break-inside: avoid;
  margin-bottom: .5rem;
  min-height: calc(var(--mm, 40) * 0.9px);
}

/* On a narrow screen a 3-column box has nothing to span into. */
@media (max-width: 640px) { .ad-kolom { grid-column: 1 / -1; } }

/* ------------------------------------------------------- reading modes */

/* "Baca" mode: same voice, readable on a phone. One column, larger type,
   and the server-side line breaks released so text can flow naturally. */
body[data-mode="baca"] .band--baris { columns: 1; column-rule: 0; }
body[data-mode="baca"] .ad-baris { font-size: 1rem; line-height: 1.45; }
body[data-mode="baca"] .ad-baris__body { white-space: normal; }
body[data-mode="baca"] .ad-baris__contact { font-size: 1.05rem; }

.mode-toggle {
  display: inline-flex; border: 1px solid var(--rule);
  font-size: .7rem; text-transform: uppercase; letter-spacing: .1em;
}
.mode-toggle button {
  font: inherit; letter-spacing: inherit; text-transform: inherit;
  background: transparent; color: var(--ink);
  border: 0; padding: .25rem .6rem; cursor: pointer;
}
.mode-toggle button[aria-pressed="true"] { background: var(--ink); color: var(--paper); }

/* ------------------------------------------------------------------ forms */

fieldset { border: 1px solid var(--rule); padding: .75rem; margin: 0; }
legend { padding: 0 .35rem; }

.field { display: block; margin-bottom: .9rem; }
.field__label {
  display: block; font-size: .7rem; text-transform: uppercase;
  letter-spacing: .12em; color: var(--ink-soft); margin-bottom: .25rem;
}
.field__hint { font-size: .72rem; color: var(--ink-faint); margin-top: .2rem; }

input[type="text"], input[type="email"], input[type="tel"], input[type="password"],
input[type="number"], input[type="date"], select, textarea {
  width: 100%; font: inherit; font-size: .9rem;
  color: var(--ink); background: var(--paper);
  border: 1px solid var(--rule); border-radius: 0;
  padding: .45rem .5rem;
}
textarea { font-family: var(--font-classified); line-height: 1.25; resize: vertical; }
input:focus-visible, select:focus-visible, textarea:focus-visible,
button:focus-visible, a:focus-visible {
  outline: 2px solid var(--spot); outline-offset: 1px;
}

.btn {
  display: inline-block; font: inherit; font-size: .8rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em; text-decoration: none;
  padding: .55rem 1.1rem; cursor: pointer;
  border: 1px solid var(--rule); border-radius: 0;
  background: var(--paper); color: var(--ink);
}
.btn--primary { background: var(--ink); color: var(--paper); }
.btn--spot { background: var(--spot); border-color: var(--spot); color: #fff; }
.btn:disabled { opacity: .45; cursor: not-allowed; }

/* ----------------------------------------------------------- ad composer */

.composer { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,22rem); gap: 2rem; align-items: start; }
@media (max-width: 900px) { .composer { grid-template-columns: 1fr; } }

/* The live preview mirrors the printed column exactly: same measure, same
   type, same wrapping. It is the single most important screen in the product. */
.preview {
  position: sticky; top: 1rem;
  border: 1px solid var(--rule); padding: .75rem;
  background: var(--paper);
}
.preview__caption {
  font-size: .65rem; text-transform: uppercase; letter-spacing: .14em;
  color: var(--ink-faint); border-bottom: 1px solid var(--rule-soft);
  padding-bottom: .3rem; margin-bottom: .5rem;
}
.preview__column { width: var(--measure); max-width: 100%; }

.ruler {
  display: flex; justify-content: space-between;
  font-size: .65rem; text-transform: uppercase; letter-spacing: .1em;
  color: var(--ink-faint); margin-top: .5rem;
  border-top: 1px solid var(--rule-soft); padding-top: .3rem;
}
.ruler__over { color: var(--spot); font-weight: 700; }

.quote { border-top: 2px solid var(--rule); margin-top: .75rem; padding-top: .5rem; }
.quote__row { display: flex; justify-content: space-between; gap: 1rem; font-size: .8rem; padding: .2rem 0; }
.quote__row span:last-child { white-space: nowrap; font-variant-numeric: tabular-nums; }
.quote__detail { font-size: .68rem; color: var(--ink-faint); }
.quote__total {
  display: flex; justify-content: space-between; gap: 1rem;
  border-top: 1px solid var(--rule); margin-top: .4rem; padding-top: .4rem;
  font-size: 1.05rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.quote__error { color: var(--spot); font-size: .8rem; font-weight: 700; }

/* The slashed price a promo produces — shown in the composer's live quote and
   on the invoice, so the discount is visible before and after booking. */
.price-tag {
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  margin: 0 0 .75rem;
}
.price-tag__was {
  color: var(--ink-faint);
  font-size: .95rem;
  font-variant-numeric: tabular-nums;
  text-decoration: line-through;
  text-decoration-color: var(--spot);
}
.price-tag__now {
  color: var(--spot);
  font-size: 1.3rem;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ misc */

.stack > * + * { margin-top: 1rem; }
.prose { max-width: 62ch; font-size: .95rem; }
.prose h2 { font-family: var(--font-display); font-size: 1.4rem; margin: 1.5rem 0 .4rem; }

.notice { border-left: 3px solid var(--spot); background: var(--spot-soft); padding: .6rem .8rem; font-size: .85rem; }
.empty { padding: 3rem 0; text-align: center; color: var(--ink-faint); font-size: .9rem; }

.tag {
  display: inline-block; font-size: .62rem; text-transform: uppercase;
  letter-spacing: .1em; padding: .1rem .35rem; border: 1px solid var(--rule-soft);
}
.tag--live { border-color: var(--spot); color: var(--spot); }

table.list { width: 100%; border-collapse: collapse; font-size: .85rem; }
table.list th, table.list td { text-align: left; padding: .45rem .5rem; border-bottom: 1px solid var(--rule-soft); }
table.list th { font-size: .68rem; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-soft); border-bottom-color: var(--rule); }
table.list td.num { text-align: right; font-variant-numeric: tabular-nums; }

.searchbar { display: flex; gap: 0; margin: .75rem 0; }
.searchbar input { border-right: 0; }


/* ------------------------------------------- sold geometry, as classes */
/* Ad sizes come from the rate card, not from arbitrary numbers, so the
   grid geometry is a closed set of classes rather than inline styles. */
.span-1 { grid-column: span 1; }
.span-2 { grid-column: span 2; }
.span-3 { grid-column: span 3; }
.span-4 { grid-column: span 4; }
.span-5 { grid-column: span 5; }
.span-6 { grid-column: span 6; }

.mm-20 { min-height: 76px; }
.mm-30 { min-height: 113px; }
.mm-40 { min-height: 151px; }
.mm-50 { min-height: 189px; }
.mm-60 { min-height: 227px; }
.mm-70 { min-height: 265px; }
.mm-80 { min-height: 302px; }
.mm-90 { min-height: 340px; }
.mm-100 { min-height: 378px; }
.mm-110 { min-height: 416px; }
.mm-120 { min-height: 454px; }
.mm-130 { min-height: 491px; }
.mm-140 { min-height: 529px; }
.mm-150 { min-height: 567px; }

@media (max-width: 640px) {
  [class*="span-"] { grid-column: 1 / -1; }
}

/* ------------------------------------------------------------------ share */

.share { border-top: 1px solid var(--rule-soft); margin-top: 1rem; }
.share__row { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .35rem; }
.share__btn { flex: 1 1 auto; text-align: center; font-size: .7rem; padding: .45rem .6rem; }

/* WhatsApp leads: it is how classifieds actually circulate here. Kept in the
   house spot colour rather than the brand green, which would be the only
   foreign colour on the page. */
.share__btn--wa { background: var(--spot); border-color: var(--spot); color: #fff; }
.share__btn--wa:hover { color: #fff; opacity: .9; }

.share__url {
  width: 100%;
  font-size: .7rem;
  padding: .35rem .4rem;
  color: var(--ink-soft);
  margin-top: .15rem;
}
.share__status {
  font-size: .68rem;
  color: var(--spot);
  min-height: 1.1em;
  margin: .3rem 0 0;
}

@media print { .share { display: none !important; } }

/* ----------------------------------------------------------- redaksi desk */

/* The desk's own navigation: a real bar, not a footnote. */
.desk-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 1.25rem;
  border-bottom: 1px solid var(--rule);
  padding: .5rem 0;
  margin-bottom: .5rem;
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .1em;
}
.desk-nav a { text-decoration: none; padding: .15rem 0; }
.desk-nav a[aria-current="page"] { color: var(--spot); font-weight: 700; }

.admin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0 1rem;
  align-items: start;
  border: 1px solid var(--rule-soft);
  padding: .9rem;
}

.admin-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
  align-items: center;
}
.admin-actions input[type="text"] { width: 9rem; font-size: .78rem; padding: .3rem; }
.admin-actions .btn { font-size: .68rem; padding: .3rem .6rem; }

/* Destructive actions are the one place this palette raises its voice. */
.btn--danger { border-color: var(--spot); color: var(--spot); }
.btn--danger:hover { background: var(--spot); color: #fff; }

/* ------------------------------------------------------ network ad slots */

/* A network ad is not the paper's own classified inventory, so it is fenced
   off and labelled rather than blended in. The height is reserved up front so
   the page never reflows when the ad loads. */
.iklan-slot {
  display: block;
  margin: 1.6rem 0;
  padding-top: .3rem;
  border-top: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
  text-align: center;
}

.iklan-slot__label {
  display: block;
  font-size: .6rem;
  text-transform: uppercase;
  letter-spacing: .18em;
  color: var(--ink-faint);
  margin-bottom: .35rem;
}

/* Reserved box. Fixed height means cumulative layout shift stays at zero
   whether the ad fills, fails, or is blocked. */
.iklan-slot__frame {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 90px;
  margin: 0 auto .5rem;
  max-width: 728px;
  overflow: hidden;
}
@media (max-width: 480px) {
  .iklan-slot__frame { min-height: 100px; max-width: 320px; }
}

.iklan-slot__preview {
  width: 100%;
  padding: 2rem 0;
  border: 1px dashed var(--rule-soft);
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Network ads are not part of the edition; they never print. */
@media print { .iklan-slot { display: none !important; } }

/* --------------------------------------------------------------- printing */

/* It is a newspaper. It should print like one. */
@media print {
  :root { --ink: #000; --rule: #000; --rule-soft: #999; --spot: #000; }
  body { font-size: 8pt; }
  .nav, .mode-toggle, .searchbar, .no-print { display: none !important; }
  .sheet { max-width: none; padding: 0; }
  .band--baris { columns: 6; }
  .ad-baris { font-size: 6.5pt; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
